简体   繁体   English

两个派生进程之间的消息队列导致msgsnd的参数无效

[英]Message queue between two forked processes causing invalid argument from msgsnd

The program creates two child processes. 该程序将创建两个子进程。 The first child process (1) reads text from stdin, removes any special chars, and spilts into words. 第一个子进程(1)从stdin读取文本,删除所有特殊字符,然后拼成单词。 That part of the program works just fine. 该程序的那部分工作正常。 Then while child (1) is splitting up the words it is sending each whole word through a message queue. 然后,当子项(1)拆分单词时,它通过消息队列发送每个完整的单词。 This part causes the invalid argument error. 这部分导致无效的参数错误。 Child 2 should then just print the message it got back to the screen. 然后,孩子2应该只将返回到屏幕的消息打印出来。

At least that's how I planned on this working. 至少这就是我计划这项工作的方式。 I'm kinda stuck and not really sure how to debug the message queue. 我有点卡住,不太确定如何调试消息队列。 Right now it's throwing an error from 现在它从抛出一个错误

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <error.h>
#include <stdlib.h>
#include <unistd.h> 
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <ctype.h>

# define QUEUE_PERMS 0644

static int message_queue = (int) 0;
static key_t key = (key_t) 0;

typedef struct message
{
  long mtype;
  char msg[100];
} mess_t;

int main(int argc, char *argv[]){

  const char delimiters[] = " ,.-!?()1234567890@#$%^&*\n";
  char *word = NULL;
  size_t buffer = 100;
  char *token;
  mess_t message;
  mess_t message2;
  int i;


  // set up a message queue
   key = ftok(__FILE__,'x');

  // create queue
   message_queue = msgget(key, QUEUE_PERMS | IPC_CREAT);
   if(message_queue == -1){
    perror("creating message queue");
   }

  // create parcer process. This tokenizes the strings
  // and send each work to the sort function(s)
  switch(fork()){
    case 0:
      // child process # 1 starts here
      key = ftok(__FILE__,'x');
      message_queue = msgget(key, QUEUE_PERMS);

      // splitting the words up here, this works fine 
      while(getline(&word, &buffer, stdin) != EOF){
        token = strtok(word, delimiters);
        while(token != NULL){
          for(i = 0; token[i]; i++){
            token[i] = tolower(token[i]);
          }
          // set type to 1 to send
          message.mtype = 1;
          // copy the word (token) over to the message struct
          strcpy(message.msg,token);

          // **** I get a send failed: Invalid argument here  *****
          if(msgsnd(key, &message, sizeof(message), MSG_NOERROR) == -1){
            perror("send failed");
          }
          token = strtok(NULL, delimiters);
        }
      }    
      break;

    case -1:
      perror("error fork\n");
      break;

    default:
      wait(NULL);
      break;
  }

  // this process should read the message an print it out
  switch(fork()){
    case 0:
    // child process # 2 starts here
      key = ftok(__FILE__,'x');
      message_queue = msgget(key, QUEUE_PERMS ); 
      msgrcv(key, &message2, sizeof(message),1, MSG_NOERROR); 
      printf("child process got %s\n", message2.msg);
      break;

    case -1:
      perror("error fork\n");
      break;

    default:
      wait(NULL);
      break;
  }

  return 0;
}

You set the message_queue message queue ID with msgget() , but you then try to send to msgsnd() using the key instead of the message queue ID. 您可以使用msgget()设置message_queue消息队列ID,但随后尝试使用key而不是消息队列ID将其发送到msgsnd()

You have the same problem with msgrcv() too. 您也有msgrcv()同样的问题。

When I fix those two, I can run the program: 修复这两个问题后,即可运行该程序:

$ ./mq
abelone apathy
child process got abelone
child process got apathy
$

I typed abelone apathy on one line, then Control-D to indicate EOF. 我在一行上键入了abelone apathy ,然后按Control-D表示EOF。

As you've got it organized, the writing process fills the message queue before the reading process is enabled. 如您所言,书写过程将在启用阅读过程之前填充消息队列。 As long as the input isn't too big, that works. 只要输入不是太大,就行。 However, you probably really want the two processes running concurrently. 但是,您可能确实希望两个进程同时运行。 You'll need to move the wait() calls to give you the concurrency. 您需要移动wait()调用来实现并发性。 (Another advantage of properly separating code into functions — it is easier to spot such problems if you hide as much as possible.) (将代码正确地分离为函数的另一个优点-如果您尽可能多地隐藏代码,则更容易发现此类问题。)

(1) Wrong value to msgsnd/msgrcv . (1) msgsnd/msgrcv值错误。 Use thre return value of msgget which is message_queue in your code. 在代码中使用msgget返回值(即message_queue

(2) Your fork code is wrong. (2)您的fork代码错误。 The parent will create one child then hit wait and wait before the 1st child dies before continuing on to create the 2nd child. 父母将创建一个孩子,然后wait并等待第一个孩子去世,然后继续创建第二个孩子。 You will want to reconsider using exit in some of places you are just using break in your switch statements. 您可能想在switch语句中刚刚使用break某些地方重新考虑使用exit

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM