【问题标题】:C - Problem with message passing between threads using queuesC - 使用队列在线程之间传递消息的问题
【发布时间】:2011-05-10 00:09:16
【问题描述】:

我正在尝试使用队列在 2 个线程之间传递消息,但到目前为止我还没有得到任何结果。当我在收到消息之后和发送之前打印消息的内容时,它似乎只是将其价值保持在范围内。我需要用 1 个服务器线程和多个客户端线程来实现它,但现在我只使用其中的 1 个。这是我的代码

struct msg                                //struct for client requests to server
{
        long mtype;
        int numResources;           //number of resources to be requested
        int ID;                     //ID associated with client thread
};                                         

int c1PID;                              //process ID variable for client thread 1
int serverPID;

key_t key1;
key_t keyS;

int msqid1;
int msqidS;

int main(int arc, char *argv[])
{
        key1 = ftok(".", '1');      //queue for client thread 1 to receive msgs from server
        msqid1 = msgget(key1, 666 | IPC_CREAT);

        keyS = ftok(".", 's');                          //general queue for server
        msqidS = msgget(keyS, 666 | IPC_CREAT);

        pthread_t threads[2];              //create an array of pthreads

        if ((serverPID = pthread_create(&threads[0], NULL, server, NULL)) != 0)
        {
                perror("server thread");
                exit(1);
        }

        if ((c1PID = pthread_create(&threads[1], NULL, client, NULL)) != 0)
        {
                perror("client thread");
                exit(1);
        }

        pthread_exit(NULL);
}

void *server()
{                                  
        struct msg request;
        size_t size = sizeof(struct msg) - offsetof(struct msg, numResources);

        while (1)
        {

                msgrcv(msqidS, &request, size, 2, 0);

                printf("received: numResources requested = %d\n", request.numResources);

                request.numResources = 9001;

                printf("sending: numResources requested = %d\n", request.numResources);

                msgsnd(msqid1, &request, size, 0);

                sleep(1);
        }
}

void *client()
{
        struct msg request;
        size_t size;
        request.numResources = 0;
        size = sizeof(struct msg) - offsetof(struct msg, numResources);

        msgsnd(msqidS, &request, size, 0);

        while(1)
        {
                msgrcv(msqid1, &request, size, 2, 0);

                printf("received: numResources requested = %d\n", request.numResources);

                request.numResources += 1;//(int)(ceil((double)(rand()%2)) + 1);

                printf("sending: numResources requested = %d\n", request.numResources);

                msgsnd(msqidS, &request, size, 0);

                sleep(1);
}

我取出了很多打印语句,但看起来是这样的:

Server thread: 
received: numResources = 9001;
sending: numResources = 9001;

client thread:
received: numResources = 1;
sending: numResources = 2;

Server thread: 
received: numResources = 9001;
sending: numResources = 9001;

client thread:
received: numResources = 2;
sending: numResources = 3;

【问题讨论】:

  • 您是在尝试实现一个客户端服务器程序,该程序将位于两台不同的机器上,还是只有两个线程相互通信?
  • 他们只是在同一台机器上互相交谈

标签: c pthreads message-queue


【解决方案1】:

编辑: sizeof(struct msg) - offsetof(struct msg, numResources);应该没问题。

但是,根据docs,您的mtype 必须是一个正整数。将其初始化为 2,因为您对 msgrecv 的调用表明只接收消息类型 2。

向所有 msgsnd/msgrecv 调用添加错误检查,这样您就可以确定自己不会默默地收到错误。

为您的 ftok 和 msgget 调用添加错误检查。

【讨论】:

  • 我最初通过 numResources 将其抵消,因为我遵循的队列教程说在 mtype 之后立即由数据成员抵消。我尝试将其更改为 ID,但似乎没有任何作用。
  • 现在我将 offsetof(struct msg, ID) 作为大小参数传递,但仍然没有运气:/我将尝试在发送/接收中添加错误消息
  • 嗯,我输入了错误捕获(如果发送/接收函数 == -1,则打印错误并退出)并返回“无效参数”。但是我尽可能地遵循了我的教程指南,我不确定哪些论点是不正确的。
  • " EINVAL 无效的 msqid 值,或非正的 mtype 值,或无效的 msgsz 值(小于 0 或大于系统值 MSGMAX)。" .您需要初始化 mtype ,如现在答案中所述。
  • 我实际上是在等待响应时在 msgsend/rcv 上阅读更多内容时初始化了 mtype,但这并没有改变任何东西。我将为队列创建添加错误检查以仔细检查。
【解决方案2】:

这是它在运行时打印的似乎有效的内容。

program starting
Msg sent from client

*****In client thread*****
Msg received by client
received: numResources requested = 0
sending: numResources requested = 1
Msg sent from client


*****In server thread*****
Msg received by server
received: numResources requested = 1
sending: numResources requested = 9001
Msg sent from server.


*****In client thread*****
Msg received by client
received: numResources requested = 9001
sending: numResources requested = 9002
Msg sent from client


*****In server thread*****
Msg received by server
received: numResources requested = 9002
sending: numResources requested = 9001
Msg sent from server.


*****In client thread*****
Msg received by client
received: numResources requested = 9001
sending: numResources requested = 9002
Msg sent from client


*****In server thread*****
Msg received by server
received: numResources requested = 9002
sending: numResources requested = 9001
Msg sent from server.


*****In client thread*****
Msg received by client
received: numResources requested = 9001
sending: numResources requested = 9002
Msg sent from client

紧接着……

program starting
Msg sent from client

*****In client thread*****
Msg received by client
received: numResources requested = 9001
sending: numResources requested = 9002
Msg sent from client


*****In server thread*****
Msg received by server
received: numResources requested = 0
sending: numResources requested = 9001
Msg sent from server.


*****In client thread*****
Msg received by client
received: numResources requested = 9002
sending: numResources requested = 9003
Msg sent from client


*****In server thread*****
Msg received by server
received: numResources requested = 9001
sending: numResources requested = 9001
Msg sent from server.


*****In client thread*****
Msg received by client
received: numResources requested = 9003
sending: numResources requested = 9004
Msg sent from client


*****In server thread*****
Msg received by server
received: numResources requested = 9001
sending: numResources requested = 9001
Msg sent from server.

这些是一个接一个地运行,中间没有对代码进行任何更改。

【讨论】:

  • 我再次运行它,它在前几个循环中给了我非常奇数的数字,但随后又回到了第一次迭代的结果,它似乎正在工作。不知道.... 编辑:第四次运行它,它给了我第二次运行的结果。我看到了一个模式……
【解决方案3】:

您的问题是您在消息队列上设置了无意义的权限。在这些行中,您使用了十进制常量 666,而您应该使用八进制常量 0666

    msqid1 = msgget(key1, 666 | IPC_CREAT);
    msqid1 = msgget(key1, 666 | IPC_CREAT);

这意味着您已经创建了具有八进制权限 01232 的队列,其中不包括读取权限 - 因此您随后的 msgget() 调用现在都以 EPERM 失败(如果您会看到检查这些调用是否有错误)。

您必须删除您的消息队列并允许您的程序以正确的权限重新创建它们。您需要使用IPC_RMID 对队列使用IPC_RMID 命令对msgctl() 执行此操作,如下程序所示:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int main(int argc, char *argv[])
{
        if (argc < 2) {
                fprintf(stderr, "Usage: %s <msqid> [<msgqid> ...]\n", argv[0]);
                return 1;
        }

        while (*++argv)
        {
                int msqid = atoi(*argv);

                printf("Removing msqid %d\n", msqid);
                if (msgctl(msqid, IPC_RMID, NULL) != 0) {
                        perror("msgctl");
                        return 2;
                }
        }

        return 0;
}

由于 SYS V 消息队列的糟糕设计,您无法再从 msgget() 获取 msqid 值,因为 msgget() 失败。要删除 msqid 值,请查看文件 /proc/sysvipc/msg

PS:

我强烈建议改用 POSIX 消息队列(mq_open()mq_send()mq_receive() 等)。界面明显改进。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    • 2014-12-12
    • 2015-06-04
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    相关资源
    最近更新 更多