c - 两个 fork 进程之间的消息队列导致来自 msgsnd 的参数无效

标签 c fork posix message-queue

程序创建了两个子进程。第一个子进程 (1) 从 stdin 读取文本,删除任何特殊字符,然后拆分成单词。该程序的那部分工作得很好。然后,当 child (1) 拆分单词时,它通过消息队列发送每个完整的单词。这部分导致无效参数错误。然后 Child 2 应该只打印它返回到屏幕的消息。

至少我是这样计划这项工作的。我有点卡住了,不太确定如何调试消息队列。现在它从

抛出错误
#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;
}

最佳答案

您使用 msgget() 设置了 message_queue 消息队列 ID,但是您随后尝试使用 发送到 msgsnd() >key 而不是消息队列 ID。

msgrcv() 也有同样的问题。

当我修复了这两个问题后,我就可以运行程序了:

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

我在一行中输入了 abelone apathy,然后 Control-D 表示 EOF。

正如您组织的那样,写入进程会在启用读取进程之前填满消息队列。只要输入不是太大,就可以。但是,您可能确实希望这两个进程同时运行。您需要移动 wait() 调用以获得并发性。 (将代码适本地分离到函数中的另一个好处是,如果您尽可能隐藏,则更容易发现此类问题。)

关于c - 两个 fork 进程之间的消息队列导致来自 msgsnd 的参数无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23506603/

相关文章:

c - Opengl 330 核心创建和使用纹理 2D

c - 解释这段代码的工作原理;子进程如何返回值以及在哪里?

c - 在 C 中,如何使用 dup2 将 STDOUT_FILENO 重定向到/dev/null,然后再重定向回其原始值?

c - C fork()和kill()同时无法正常工作?

c - Unix 域 SOCK_DGRAM 和 SOCK_SEQPACKET 之间的区别?

c - 如何用 C 重写这个检查

在 C 中检查字符串数组中的字符串

c# - 为什么 "dtoa.c"包含这么多代码?

java - 如何在 java(android) 中以 posix 格式打印本地时区?

c++ - 通过 `kill`生成的SIGSEGV是否特殊?