C - Problem with message passing between threads using queues
I'm trying to pass messages between 2 threads using a queue, but I haven't gotten any results so far. When I print the contents of the message after it's received and before it's sent, it only seems to keep its value within the tread. I need to implement it with 1 server thread and multiple client threads, but for now I'm only using 1 of each. Here's my code
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);
}
I took out a lot of my print statements, but it looks something like this:
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;
Your problem is that you have set nonsense permissions on your message queues. In these lines, you have used a decimal constant 666
where you should have used an octal constant 0666
:
msqid1 = msgget(key1, 666 | IPC_CREAT);
msqid1 = msgget(key1, 666 | IPC_CREAT);
This means that you've created the queues with octal permissions 01232
, which doesn't include read permission - so your subsequent msgget()
calls are all now failing with EPERM
(which you'll see if you check those calls for errors).
You will have to remove your message queues and allow your program to re-create them with the correct permissions. You need to use the msqid
for the queue with the IPC_RMID
command to msgctl()
to do this, as in the following program:
#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;
}
Due to the awful design of SYS V message queues, you can't get the msqid
values from msgget()
anymore, because msgget()
fails. To get the msqid
values to remove, look in the file /proc/sysvipc/msg
.
PS:
I highly recommend using POSIX message queues instead (mq_open()
, mq_send()
, mq_receive()
etc.). The interface is significantly improved.
Here's what it printed on the run that appeared to work.
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
And immediately after....
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.
These were run 1 after the other with no changes made to the code in between.
Edit: The sizeof(struct msg) - offsetof(struct msg, numResources); should be ok.
But, your mtype
needs to be, as per the docs, a positive integer. Initialize it to 2, as your calls to msgrecv says to receive only message type 2.
Add error checking to all the msgsnd/msgrecv calls , so you're sure you're not silently getting errors.
Add error checking to your ftok and msgget calls.
精彩评论