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

Linux 为什么macOS和Ubuntu上的消息队列结果不同,linux,message-queue,ubuntu-16.04,macos-sierra,Linux,Message Queue,Ubuntu 16.04,Macos Sierra,最近我在学习Linux上的进程通信。我写了一个C程序来做以下事情: 进程A设置消息队列(如邮箱) 进程B向队列发送三条消息“111”、“222”、“333” 进程C从队列中以“333”、“111”、“222”的顺序读取消息 进程D删除队列 我首先在Ubuntu 16.04上编写了这个程序,它工作得很好,正如我所想: 然而,当我编译相同的代码并尝试在macOS(Sierra 10.12.3)上运行时,结果与Ubuntu上的结果不同: 无论我如何更改代码(例如,在进程a中睡眠几秒钟),队列总是在

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

  • 进程A设置消息队列(如邮箱)
  • 进程B向队列发送三条消息“111”、“222”、“333”
  • 进程C从队列中以“333”、“111”、“222”的顺序读取消息
  • 进程D删除队列
  • 我首先在Ubuntu 16.04上编写了这个程序,它工作得很好,正如我所想:

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

    无论我如何更改代码(例如,在进程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);
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #定义最大文本1024
    结构mymsg123
    {
    长整数优先级;
    字符文本[最大文本];
    };
    int main()
    {
    int msgid=-1;//消息id
    struct mymsg123 data;//要发送的消息
    //在进程A中设置消息队列(邮箱)
    msgid=msgget((键)12340666 | IPC|u CREAT);
    如果(msgid==-1)
    {
    fprintf(stderr,“进程A中的msgget失败,错误:%d\n”,错误号);
    退出(退出失败);
    }
    printf(“在进程A中创建的邮箱”);
    pid_t pid=fork();//创建进程B
    if(pid<0){fprintf(stderr,“Fork在进程A中失败”);exit(exit_FAILURE);}
    //子进程B
    否则如果(pid==0)
    {
    常量字符msg1[]=“111”;
    //设置第一条消息
    data.priority=2;
    strcpy(data.text,msg1);
    //发送第一条消息
    if(msgsnd(msgid,(void*)和数据,最大文本,0)=-1)
    {
    fprintf(stderr,“发送msg1时进程B中的msgsnd失败\n”);
    退出(退出失败);
    }
    printf(“已将消息%s,优先级%ld发送到邮箱\n”,data.text,data.priority);
    常量字符msg2[]=“222”;
    //设置第二条消息
    data.priority=3;
    strcpy(data.text,msg2);
    //发送第二条消息
    if(msgsnd(msgid,(void*)和数据,最大文本,0)=-1)
    {
    fprintf(stderr,“发送msg2时在进程B中msgsnd失败\n”);
    退出(退出失败);
    }
    printf(“已将消息%s,优先级%ld发送到邮箱\n”,data.text,data.priority);
    常量字符msg3[]=“333”;
    //设置第三条消息
    data.priority=1;
    strcpy(data.text,msg3);
    //发送第三条消息
    if(msgsnd(msgid,(void*)和数据,最大文本,0)=-1)
    {
    fprintf(stderr,“发送msg3时进程B中的msgsnd失败\n”);
    退出(退出失败);
    }   
    printf(“已将消息%s,优先级%ld发送到邮箱\n”,data.text,data.priority);
    }
    //父进程A
    其他的
    {
    pid_t pid=fork();//创建进程C
    if(pid<0){fprintf(stderr,“Fork在进程A中失败”);exit(exit_FAILURE);}
    //子进程C
    否则如果(pid==0)
    {
    //接收优先级1消息
    长整数优先级=1;
    if(msgrcv(msgid,(void*)和数据,BUFSIZ,优先级,0)=-1)
    {
    fprintf(stderr,“当接收到优先级为1的消息:%d\n”时,msgrcv在进程C中出现错误失败,错误号);
    退出(退出失败);
    }
    printf(“从邮箱%s\n接收到进程C中优先级为1的消息”,data.text);
    //接收优先级2消息
    优先级=2;
    if(msgrcv(msgid,(void*)和数据,BUFSIZ,优先级,0)=-1)
    {
    fprintf(stderr,“当接收到优先级为2的消息:%d\n时,msgrcv在过程C中出错失败”,errno);
    退出(退出失败);
    }
    printf(“从邮箱%s\n接收到进程C中优先级为2的消息”,data.text);
    //接收优先级为3的消息
    优先级=3;
    if(msgrcv(msgid,(void*)和数据,BUFSIZ,优先级,0)=-1)
    {
    fprintf(stderr,“当接收到优先级为3的消息:%d\n”时,msgrcv在进程C中失败,并出现错误”,errno);
    退出(退出失败);
    }
    printf(“在进程C中从邮箱%s\n接收到优先级为3的消息”,data.text);
    }
    //父进程A
    其他的
    {
    pid_t pid=fork();//创建进程D
    if(pid<0){fprintf(stderr,“Fork在进程A中失败”);exit(exit_FAILURE);}
    //子进程D
    否则如果(pid==0)
    {
    //睡眠(10);
    如果(msgctl(msgid,IPC_RMID,0)=-1)
    {
    fprintf(stderr,“进程D中的msgctl(IPC_RMID)失败”);
    退出(退出失败);
    }
    printf(“在进程D中删除的邮箱”);
    }
    //父进程A
    其他的
    ;
    }
    }
    //睡眠(10);
    退出(退出成功);
    }
    

    提前谢谢

    如果您打印错误消息本身,而不仅仅是错误代码,这将非常有用

    无论如何,我认为这是因为,但在Linux上通常是16384。再加上您的
    MAX_TEXT
    大小为1024,第三条消息无法发送,因为队列已满。它可能会一直阻塞,直到第一个
    msgrcv
    调用将第一条消息出列,从而释放空间,但macOS没有为此提供手册页,因此我将退出Linux页面

    无论如何,您有一个竞争条件,因为进程D将立即删除消息队列,而不等待它变为空。因此,如果进程B由于队列已满而阻塞,而进程D将其删除,那么进程B将返回一个错误。但这一切都取决于进程的调度,因此也取决于竞争条件

    你可以