【问题标题】:Why msgsnd() and msgrcv() can't run well?为什么 msgsnd() 和 msgrcv() 不能正常运行?
【发布时间】:2018-11-11 04:43:35
【问题描述】:

msgsnd() 和 msgrcv() 在同一个函数中,和第一个例子一样运行良好。

main.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>


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

    pid_t pid1;
    pid_t pid2;
    pid_t pid3;
    pid_t pid4;

    if ((pid1 = fork()) < 0) {
        printf("fork error\n");
    } else if (pid1 == 0){
        printf("I am in First process\n");
        int nodeId = 1;
        //cmc_init(nodeId);
        test2(nodeId);
        return 0;

    }

    if ((pid2 = fork()) < 0) {
        printf("fork error\n");
    } else if (pid2 == 0){
        printf("I am in second process\n");
        int nodeId = 2;
        //cmc_init(nodeId);
        test2(nodeId);
        return 0;

    } 

    if ((pid3 = fork()) < 0) {
        printf("pid3 fork error\n");
    } else if (pid3 == 0) {
        printf("I am in Third process\n");
        int nodeId = 3;
        //cmc_init(nodeId);
        test2(nodeId);
        return 0;
    } 

    if ((pid4 = fork()) < 0) {
        printf("pid4 fork error\n");
    } else if (pid4 == 0) {
        printf("I am in Fourth process\n");
        int nodeId = 4;
        //cmc_init(nodeId);
        //test2(nodeId);
        return 0;
    } 

    if (waitpid(-1, NULL, 0) < 0) {
        printf("wait1 error\n");
    }   
    sleep(3);


    return 0;
}

comproc.c

typedef struct Msg_context {
    int nodeId;

} Msg_context;
void test2(int nodeId)
{
    int i = 1;
    for (i = 1; i <= 3; i++) {
        if (i == nodeId) {
            continue;
        }
        int msgid = -1;
        Msg_context msgSend;

        msgid = msgget((key_t)i, 0666 | IPC_CREAT);


        if (msgid == -1) {
            printf("msgid == -1\n");
        }

        msgSend.nodeId = nodeId;
        if (msgsnd(msgid, (void *)&msgSend, 4, 0) == -1) {
            printf("send message error\n");
        }
    }

    //com_process_send(nodeId);

    sleep(1);
    while (1) {
        //com_process_recv(nodeId);
        int msgrecvId = -1;
        Msg_context msgRecv;
        msgrecvId = msgget((key_t)nodeId, 0666 | IPC_CREAT);


        if (msgrecvId == -1) {
            printf("msgrecvId == -1\n");
        }

        if (msgrcv(msgrecvId, (void *)&msgRecv, BUFSIZ, 0, 0) == -1) {
            printf("send message error\n");
        }
        printf("[recv] nodeId = %d, recv.nodeId = %d\n", nodeId, msgRecv.nodeId);

    }


}

效果很好,结果:

I am in First process
[recv] nodeId = 2, recv.nodeId = 1
[recv] nodeId = 3, recv.nodeId = 1
I am in second process
[recv] nodeId = 1, recv.nodeId = 2
[recv] nodeId = 3, recv.nodeId = 2
I am in Third process
[recv] nodeId = 1, recv.nodeId = 3
[recv] nodeId = 2, recv.nodeId = 3
I am in Fourth process

但是当我将 msgrcv() 放入另一个函数时,它不能正常工作。 像这样:

comproc.c

typedef struct Msg_context {
    int nodeId;

} Msg_context;
int com_process_recv(int nodeId)
{

    int msgrecvId = -1;
    Msg_context msgRecv;
    msgrecvId = msgget((key_t)nodeId, 0666 | IPC_CREAT);


    if (msgrecvId == -1) {
        printf("msgrecvId == -1\n");
    }

    if (msgrcv(msgrecvId, (void *)&msgRecv, BUFSIZ, 0, 0) == -1) {
        printf("send message error\n");
    }
    printf("[recv] nodeId = %d, recv.nodeId = %d\n", nodeId, msgRecv.nodeId);



}
void test2(int nodeId)
{
    int i = 1;
    for (i = 1; i <= 3; i++) {
        if (i == nodeId) {
            continue;
        }
        int msgid = -1;
        Msg_context msgSend;

        msgid = msgget((key_t)i, 0666 | IPC_CREAT);


        if (msgid == -1) {
            printf("msgid == -1\n");
        }

        msgSend.nodeId = nodeId;
        if (msgsnd(msgid, (void *)&msgSend, 4, 0) == -1) {
            printf("send message error\n");
        }
    }

    //com_process_send(nodeId);

    sleep(1);
    while (1) {
        com_process_recv(nodeId);


    }


}

结果是这样的:

I am in First process
[recv] nodeId = 2, recv.nodeId = 1
I am in second process
[recv] nodeId = 1, recv.nodeId = 2
[recv] nodeId = 3, recv.nodeId = 2
I am in Third process
[recv] nodeId = 2, recv.nodeId = 3
[recv] nodeId = 1, recv.nodeId = 3
I am in Fourth process

或者像这样:

I am in First process
[recv] nodeId = 2, recv.nodeId = 1
[recv] nodeId = 3, recv.nodeId = 3, ret = 4
I am in second process
[recv] nodeId = 1, recv.nodeId = 2
[recv] nodeId = 3, recv.nodeId = 2
I am in Third process
[recv] nodeId = 1, recv.nodeId = 3
[recv] nodeId = 2, recv.nodeId = 3
I am in Fourth process

但是,但是,如果我也将 msgsnd() 放入另一个函数中,它会再次正常工作。

comproc.c

typedef struct Msg_context {
    int nodeId;

} Msg_context;

int com_process_send(int nodeId) 
{
    int i = 1;
    for (i = 1; i <= 3; i++) {
        if (i == nodeId) {
            continue;
        }
        int msgid = -1;
        Msg_context msgSend;

        msgid = msgget((key_t)i, 0666 | IPC_CREAT);


        if (msgid == -1) {
            printf("msgid == -1 in %s with nodeId = %d\n", __FUNCTION__, nodeId);
        }
        msgSend.nodeId = nodeId;
        //int length = sizeof(msgSend.nodeId);

        int ret = msgsnd(msgid, (void *)&msgSend, 4, 0);
        if (ret == -1) {
            printf("send message error in %s with nodeId = %d\n", __FUNCTION__, nodeId);
        }

        printf("[send] nodeId = %d, dest msg = %d\n", nodeId, i);

    }
    return 0;
}


int com_process_recv(int nodeId)
{

    int msgrecvId = -1;
    Msg_context msgRecv;
    msgrecvId = msgget((key_t)nodeId, 0666 | IPC_CREAT);


    if (msgrecvId == -1) {
        printf("msgrecvId == -1\n");
    }

    if (msgrcv(msgrecvId, (void *)&msgRecv, BUFSIZ, 0, 0) == -1) {
        printf("send message error\n");
    }
    printf("[recv] nodeId = %d, recv.nodeId = %d\n", nodeId, msgRecv.nodeId);



}

void test2(int nodeId)
{


    com_process_send(nodeId);

    sleep(1);
    while (1) {
        com_process_recv(nodeId);


    }


}

所以这很奇怪,对吧?我不明白为什么会这样。所以我非常希望你们能帮助我理解这一点。非常感谢!!!

【问题讨论】:

  • 您正在运行多个进程,所有进程都从同一个消息队列中读取数据。它们可以以不可预知的顺序运行,对程序的微小更改可能会影响时间。
  • 我的任务是多个进程将消息写入同一个消息队列,但我只是让第一个进程从第一个消息队列中读取。从第二个消息队列中读取的第二个进程。等等。我该怎么办?
  • 我明白了,我看错了代码。但是没有办法知道哪个进程正在打印每个[recv] 消息。将进程 ID 放在该行中。
  • 第一个nodeId是进程id。因为在第一个进程中,我使nodeId = 1。第二个进程,nodeId = 2。依此类推。

标签: linux process ipc message-queue msgrcv


【解决方案1】:

根据我在您的 cmets 中读到的内容,如果您希望不同的进程只读发送给它们的消息,您应该查看 msgrcv()msgtyp 参数

来自手册页:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

参数 msgtyp 指定请求的消息类型如下:

如果 msgtyp 为 0,则读取队列中的第一条消息。

如果 msgtyp 大于 0,则读取队列中 msgtyp 类型的第一条消息,除非在 msgflg 中指定了 MSG_EXCEPT,在这种情况下,将读取队列中类型不等于 msgtyp 的第一条消息。

如果 msgtyp 小于 0,则将读取队列中最低类型小于或等于 msgtyp 绝对值的第一条消息。

在你的情况下,调用

    msgrcv(msgrecvId, (void *)&msgRecv, BUFSIZ, 0, nodeId) == -1)

将帮助您从第一个消息队列读取第一个进程,从第二个 msq 读取第二个进程等...

【讨论】:

  • 非常感谢!有用。我发现我没有清楚地理解消息队列。我知道 msgtyp 以及它是如何工作的。但它受到我之前使用的消息队列的影响。一个线程有一个消息队列。所以我想我有四个进程,它需要四个消息队列。其实只需要一个消息队列,用msgtyp来区分即可。
  • @mHuster 是的,你是真的;不是 4 个不同的消息队列,而是同一个消息队列中的 4 个不同的消息类型,对类型有一个过滤器
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-09
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多