【问题标题】:Message queue between two forked processes causing invalid argument from msgsnd两个分叉进程之间的消息队列导致来自 msgsnd 的参数无效
【发布时间】:2014-06-23 18:28:03
【问题描述】:

程序创建了两个子进程。第一个子进程 (1) 从标准输入读取文本,删除任何特殊字符,然后拆分为单词。该程序的那部分工作得很好。然后,当孩子 (1) 拆分单词时,它通过消息队列发送每个完整的单词。这部分导致无效参数错误。然后,孩子 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;
}

【问题讨论】:

  • 一个建议:使用函数来封装发送者和接收者的动作。然后,您可以简化您的 main() 函数,以便它在正确的位置简单地调用这些函数。你的代码很不错;它通过了我的编译测试(gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wold-style-declaration -Werror mq.c -o mq),改动很小(int main(void),因为既没有使用argc,也没有使用argv;并且在包含任何标题之前#define _XOPEN_SOURCE 700)。那是高度赞扬;很少有程序能如此接近。
  • 是的,我几乎用我能想到的所有标志进行编译。这样更难犯愚蠢的错误。
  • 那很好;它使为您调试问题变得更容易(也更有趣)。在 fork 之前,您可能需要考虑连接到消息队列 (msgget());减少重复。如果调用perror() 来报告错误,您将需要担心它会返回。我推荐一个函数(惊喜,惊喜)来进行错误报告和退出。它可以是简单的(单个字符串参数,如perror())或灵活的(格式字符串和变量参数,如printf())。我的生产代码可配置添加程序名称、时间、PID等。
  • 您可以在C Minishell -- adding pipelines 中找到我的stderr.hstderr.c 的基本但有效的版本
  • 太棒了!谢谢您的帮助。我会努力把东西分解成函数。这是我需要养成的一个习惯。

标签: c fork posix message-queue


【解决方案1】:

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

msgrcv() 也有同样的问题。

当我修复这两个时,我可以运行程序:

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

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

按照您的安排,写入过程会在启用读取过程之前填充消息队列。只要输入不是太大,就可以了。但是,您可能真的希望这两个进程同时运行。您需要移动 wait() 调用以提供并发性。 (将代码正确分离为函数的另一个好处——如果你尽可能地隐藏,就更容易发现这些问题。)

【讨论】:

  • 谢谢!我明白你说的分裂是什么意思。我得到了奇怪的结果,其中只有几个单词从较大的字符串中通过。不过,我仍然很高兴有些事情正在发生!
【解决方案2】:

(1) msgsnd/msgrcv 的值错误。在您的代码中使用msgget 的返回值,即message_queue

(2) 您的fork 代码错误。父母将创建一个孩子,然后点击wait 并在第一个孩子死亡之前等待,然后继续创建第二个孩子。您可能需要重新考虑在某些地方使用 exit,而您只是在 switch 语句中使用 break

【讨论】:

    猜你喜欢
    • 2015-12-17
    • 2017-08-25
    • 2011-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-09
    相关资源
    最近更新 更多