C - 使用队列在线程之间传递消息的问题

时间:2010-11-15 01:23:28

标签: c pthreads message-queue

我正在尝试使用队列在两个线程之间传递消息,但到目前为止我还没有得到任何结果。当我在收到邮件之后和邮件发送之前打印邮件内容时,它似乎只能保持其价值。我需要用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;

3 个答案:

答案 0 :(得分:2)

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

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

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

您必须删除邮件队列,并允许程序使用正确的权限重新创建它们。您需要使用msqid作为队列,使用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消息队列设计糟糕,您无法再从msqid获取msgget()值,因为msgget()失败。要获取要移除的msqid值,请查看文件/proc/sysvipc/msg

<强> PS:

我强烈建议您使用POSIX消息队列(mq_open()mq_send()mq_receive()等)。界面得到了显着改善。

答案 1 :(得分:1)

这是它在运行中打印出来的效果。

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.

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

答案 2 :(得分:0)

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

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

为所有msgsnd / msgrecv调用添加错误检查,因此您确定没有默默地收到错误。

将错误检查添加到您的ftok和msgget调用中。