C - проблема с передачей сообщений между потоками с использованием очередей - PullRequest
2 голосов
/ 15 ноября 2010

Я пытаюсь передать сообщения между двумя потоками, используя очередь, но пока не получил никаких результатов.Когда я печатаю содержимое сообщения после того, как оно получено и до того, как оно отправлено, кажется, что оно только сохраняет его значение в протекторе.Мне нужно реализовать это с 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 ]

2 голосов
/ 15 ноября 2010

Ваша проблема в том, что вы установили бессмысленные разрешения для своих очередей сообщений. В этих строках вы использовали десятичную константу 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 голос
/ 15 ноября 2010

Вот что он напечатал на ходу, который, казалось, работал.

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.

Они были запущены 1 за другим без измененийсделано в коде между ними.

0 голосов
/ 15 ноября 2010

Редактировать: sizeof (struct msg) - offsetof (struct msg, numResources);должно быть в порядке.

Но ваш mtype должен быть, согласно документам , положительным целым числом.Инициализируйте его как 2, так как ваши вызовы msgrecv говорят, что вы должны получать сообщения только типа 2.

Добавьте проверку ошибок ко всем вызовам msgsnd / msgrecv, так что вы уверены, что не будете молча получать ошибки.

Добавьте проверку ошибок в вызовы ftok и msgget.

...