为什么macOS和Ubuntu上的消息队列结果不同

时间:2017-04-28 01:12:22

标签: linux message-queue ubuntu-16.04 macos-sierra

最近我在Linux上学习进程通信。我写了一个C程序来做以下事情:

  1. 进程A设置消息队列(如邮箱)
  2. 进程B发送三条消息" 111"," 222"," 333"为了队列。
  3. 进程C按照" 333"," 111"," 222"的顺序读取消息。从队列中。
  4. 进程D删除队列。
  5. 我首先在Ubuntu 16.04上编写了这个程序,它的工作正常我想:

    Results on Ubuntu 16.04

    然而,当我编译相同的代码并尝试在macOS(Sierra 10.12.3)上运行时,结果与Ubuntu上的结果不同:

    Results on macOS

    无论我如何更改代码(例如,在进程A中休眠几秒钟),总是在第三条消息发送之前删除队列。

    这是我的代码:

    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/msg.h>
    #include <sys/types.h>
    #include <errno.h>
    
    #define MAX_TEXT 1024
    
    struct mymsg123
    {
            long int priority;
            char text[MAX_TEXT];
    };
    
    int main()
    {
        int msgid = -1; //message id
        struct mymsg123 data; //message to send
    
        //set up message queue(mailbox) in Process A
        msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
        if(msgid == -1)
        {
                fprintf(stderr, "msgget failed in Process A with error: %d\n", errno);
                exit(EXIT_FAILURE);
        }
        printf("Mailbox created in Process A\n");
    
        pid_t pid = fork(); //to create Process B
        if (pid < 0) {fprintf(stderr, "Fork failed in Process A"); exit(EXIT_FAILURE); }
        //child Process B
        else if (pid == 0)
        {
            const char msg1[] = "111";
            //set the first message
            data.priority = 2;
            strcpy(data.text, msg1);
            //send the first message
            if (msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
            {
                fprintf(stderr, "msgsnd failed in Process B when sending msg1\n");
                exit(EXIT_FAILURE);
            }
            printf("Sent msg %s, priority %ld to mailbox\n", data.text, data.priority);
    
            const char msg2[] = "222";
            //set the second message
            data.priority = 3;
            strcpy(data.text, msg2);
            //send the second message
            if (msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
            {
                fprintf(stderr, "msgsnd failed in Porcess B when sending msg2\n");
                exit(EXIT_FAILURE);
            }
            printf("Sent msg %s, priority %ld to mailbox\n", data.text, data.priority);
    
    
            const char msg3[] = "333";
            //set the third message
            data.priority = 1;
            strcpy(data.text, msg3);
            //send the third message
            if (msgsnd(msgid, (void*)&data, MAX_TEXT, 0) == -1)
            {
                fprintf(stderr, "msgsnd failed in Process B when sending msg3\n");
                exit(EXIT_FAILURE);
            }   
            printf("Sent msg %s, priority %ld to mailbox\n", data.text, data.priority);
        }
        //parent Process A
        else
        {
            pid_t pid = fork(); //to create Process C
            if (pid < 0) {fprintf(stderr, "Fork failed in Process A"); exit(EXIT_FAILURE); }
            //child process C
            else if (pid == 0)
            {
                //receiving priority 1 message
                long int priority = 1;
                if(msgrcv(msgid, (void*)&data, BUFSIZ, priority, 0) == -1)
                {
                    fprintf(stderr, "msgrcv failed with error in Process C when receiving priority 1 msg: %d\n", errno);
                    exit(EXIT_FAILURE);
                }
                printf("Received priority 1 message in Process C from mailbox: %s\n", data.text);
                //receiving priority 2 message
                priority = 2;
                if(msgrcv(msgid, (void*)&data, BUFSIZ, priority, 0) == -1)
                {
                    fprintf(stderr, "msgrcv failed with error in Prcess C when receiving priority 2 msg: %d\n", errno);
                    exit(EXIT_FAILURE);
                }
                printf("Received priority 2 message in Process C from mailbox: %s\n", data.text);
                //receiving priority 3 message
                priority = 3;
                if(msgrcv(msgid, (void*)&data, BUFSIZ, priority, 0) == -1)
                {
                    fprintf(stderr, "msgrcv failed with error in Process C when receiving priority 3 msg: %d\n", errno);
                    exit(EXIT_FAILURE);
                }
                printf("Received priority 3 message in Process C from mailbox: %s\n", data.text);
            }
            //parent Process A
            else
            {
                pid_t pid = fork(); //to create Process D
                if (pid < 0) {fprintf(stderr, "Fork failed in Process A"); exit(EXIT_FAILURE); }
                //child process D
                else if (pid == 0)
                {
                    //sleep(10);
                    if (msgctl(msgid, IPC_RMID, 0) == -1)
                    {
                        fprintf(stderr, "msgctl(IPC_RMID) failed in Process D\n");
                                exit(EXIT_FAILURE);
                    }
                    printf("Mailbox deleted in Process D\n");
                }
                //parent Process A
                else
                    ;
            }
        }
        //sleep(10);
    
        exit(EXIT_SUCCESS);
    }
    

    高级谢谢!

1 个答案:

答案 0 :(得分:1)

如果您打印错误消息本身而不仅仅是错误代码,将会很有帮助。

无论如何,我认为这是因为the message queue size appears to be 2048 bytes on macOS,但在Linux上通常是16384。加上MAX_TEXT大小为1024,当队列已满时,无法发送第三条消息。它可能会阻塞,直到第一个msgrcv调用出列第一条消息,释放空间,但是macOS没有给出man页面,所以我要离开Linux页面。

无论如何,您都有竞争条件,因为进程D会立即删除消息队列,而不会等待它变空。因此,如果进程B由于队列已满而阻塞,并且进程D将其删除,则B将返回错误。但这完全取决于过程的安排,因此也就是竞争条件。

您可以在macOS中更改队列大小,但需要具有超级用户权限才能使其生效。您可以通过将MAX_TEXT定义减少到128并验证它是否适用于两者来验证这一点而不以root身份运行。