views:

394

answers:

1

I have the following application which replicates an issue I'm having in a larger application with system v message queues. basically, the main function generates a key, then creates a message queue with msgget(). Then 3 forks are spawned, each with a different id. each of them runs msgrcv with a different posative number (so they are waiting for different messages).

Main then sleeps for a few seconds a sends a message to id = 3. However it isn't the third thread that wakes up but a different one instead. This code is completely isolated so you can try it out yourself. What's wrong with this code?

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

struct dummy_struct {
    long mtype;
    char message[255];
};

int msg_queue_id;
void recv_thread(int id);

int main(int argc, char **argv)
{
    int i;
    key_t key;
    struct dummy_struct dummy = { 3, "hello" };

    //create a unique key
    if (key = ftok("/mnt/mydocuments/code/sys_v_fork_test/main.c", 'a') == -1)
    {
     printf("ftok didn't work\n");
     exit(1);
    }

    //create the unix sys 5 message queue
    if ((msg_queue_id = msgget(key, 0644 | IPC_CREAT)) == -1)
    {
     printf("msgget failed\n");
     exit(1);
    }
    else
     printf("my message queue id: %i\n", msg_queue_id);

    //fork off multiple recievers
    for (i = 1; i < 4; i++) // <- NOTE: 1 -> 4
    {
     if (fork() == 0)
      recv_thread(i);
    }

    printf("sleeping\n");
    sleep(5);

    //wait a little then send a message

    printf("sending message\n");
    if (msgsnd(msg_queue_id, &dummy, sizeof(struct dummy_struct), 0) == -1)
    {
     printf("msgsnd failed\n");
    }
    printf("main thread exiting");
    _exit(0);
}

void recv_thread(int id)
{
    struct dummy_struct dummy;

    printf("recv_thread with id: %i\n", id);

    if (msgrcv(msg_queue_id, &dummy, sizeof(struct dummy_struct), id, 0) == -1)
     printf("error in msgrcv\n");
    else
     printf("thread %i got %s back\n", id, dummy.message);
}

If I wait for 2 that means messages whose struct contains a mtype set to exactly 2. 3 for 3 and so one. My point of reference was this guide: http://www.ecst.csuchico.edu/~beej/guide/ipc/mq.html. Can anyone help please? (you may need to modify the ftok line of code to point to a valid file on your own machine to test successfully). I'm running Fedora 10 on an EeePC 1000H

+1  A: 

Ahh think i've fixed it. It's because I was using an int rather than a long for the first member set in the structure for the "mtype". passing in { 1l, "hello" } instead and changing the definition of i to long seems to have fixed it

Philluminati
Per POSIX, the return value from msgget() is an int, not a long. Per POSIX, the first argument to msgsnd() is an int, not a long. If you're working 32-bit, you may be OK; if you've got your prototypes in scope (as you seem to have), the C compiler will clean up for you, too.
Jonathan Leffler
You are aware of http://www.opengroup.org/onlinepubs/009695399/toc.htm, aren't you? It's the POSIX spec. You also need your local spec in case the platform is not POSIX-compliant.
Jonathan Leffler
Also, your code only forks 3 children; using 4 as the constant is confusing. Also, '3 forks are spawned' is very odd jargon. '3 children are forked' would be Linux-speak; '3 children are spawned' would be OK, though not dreadfully precise since there is a posix_spawn() which deals with spawn.
Jonathan Leffler
sorry I edited it because I used the word "message queue id" when I should have said the structures first mtype
Philluminati