Mike Henke
Mike Henke

Reputation: 643

Using fork() incorrectly?

I'm trying to use fork() to implement a message queue. Here's what I've got.

#define DATA_SIZE 256
#define BUFF_SIZE 4096

int main(void) {
    // seed the random number generator
    srand(time(NULL));

    // Parent and Ground Truth Buffers
    char ground_truth[BUFF_SIZE]    = {0};  // used to verify
    char producer_buffer[BUFF_SIZE] = {0};  // used by the parent
    int i = 0;  
    int msqid = 0;
    int rc;
    pid_t msq_pid;

    for (i = 0; i < BUFF_SIZE; ++i) {
        producer_buffer[i] = ground_truth[i] = rand() % 256;
    }

    const key_t s_msq_key = 1337;  // used to create message queue ipc
    const char *const p_msq_key = "/OS_MSG";

    msqid = msgget(s_msq_key, IPC_CREAT | 0660);

    msq_pid = fork();

    if(msq_pid == -1){
       perror("error forking");
       exit(1);
    }

    if(msq_pid > 0){
        rc = msgsnd(msqid, (void*)p_msq_key, sizeof(producer_buffer), 0);
        printf("MESSAGE SENT\n");
        if(rc < 0){
            perror("message send failed");
            exit(1);
        }
        return 1;
    } else {
        if(memcmp(producer_buffer, ground_truth, DATA_SIZE) == 0){
            printf("MESSAGE REC");
            return 1;
        }
        exit(1);
    }

return 0;
}

I added my actual problem. Hopefully this isn't too much. This is a homework assignment but I didn't want to just get help with the code. Once again, the only result that I am getting is MESSAGE REC rather than MESSAGE SENT followed by MESSAGE REC

EDIT:

Okay, I added an error check for msq_pid == -1. I also noticed that when I restarted my Virtual Machine, I was able to get both MESSAGE SENT and MESSAGE REC. After several more runs of the program, I then began only receiving MESSAGE REC. Can someone explain this?

Upvotes: 0

Views: 130

Answers (2)

user3629249
user3629249

Reputation: 16540

several of the system calls are being used incorrectly.

The returned status from several of the system calls are being ignored

The following code:

  1. cleanly compiles
  2. performs the desired operation
  3. handles all the error conditions

now, the code:

#include <stdio.h>
#include <stdlib.h>

#include <time.h>    //time()

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

#include <unistd.h>  //fork()

#include <string.h>  //memcmp()


#define MAX_MSG_LEN (10)
#define ACT_MSG_LEN (8)

// Parent and Ground Truth Buffers
struct msgbuf
{
    long mtype;       /* message type, must be > 0 */
    char mtext[ MAX_MSG_LEN ];    /* message data */
};

struct msgbuf ground_truth;  // used to verify
struct msgbuf producer_buffer = {1,"message"}; // used by the parent

int main(void)
{
    // seed the random number generator
    srand((unsigned)time(NULL));



    //int i = 0;
    int msqid = 0;
    int rc;
    pid_t msq_pid;
    ssize_t rcvStatus;

    const key_t s_msq_key = 1337;  // used to create message queue ipc
    //const char *const p_msq_key = "/OS_MSG";

    msqid = msgget(s_msq_key, IPC_CREAT | 0660);
    if( -1 == msqid )
    {// then msgget failed
        perror( "msgget failed");
        exit( EXIT_FAILURE );
    }

    // implied else, msgget successful

    msq_pid = fork();

    while(1)
    {
        switch( msq_pid )
        {
            case -1:
                perror("error forking");
                exit( EXIT_FAILURE );
                break;

            default:  // parent process
                rc = msgsnd(msqid, &producer_buffer, sizeof producer_buffer, 0);
                printf("MESSAGE SENT: %s\n", producer_buffer.mtext);
                if(rc < 0)
                {
                    perror("message send failed");
                    exit( EXIT_FAILURE );
                }
                break;

            case 0:   // child process
                rcvStatus = msgrcv( msqid, &ground_truth, sizeof( ground_truth ), 0, 0);
                if( -1 == rcvStatus )
                { // then msgrcv failed
                    perror( "msgrcv failed" );
                    exit( EXIT_FAILURE );
                }

                // implied else, msgrcv successful

                if(memcmp(producer_buffer.mtext, ground_truth.mtext, ACT_MSG_LEN) == 0)
                {
                    printf("MESSAGE REC %s\n", ground_truth.mtext);
                }

                else
                {
                    printf( "msg Sent: '%s' does not match msg Recv: '%s'\n", producer_buffer.mtext, ground_truth.mtext);
                }
                break;
        } // end switch
    } // end while forever
} // end function: main

Upvotes: 0

xmonk
xmonk

Reputation: 545

Per the fork() man page it seems your problem is that you have the child and parent inverted. fork() returns 0 to the child process, it returns > 0 to the parent, and returns -1 on error. So in your code you should have:

if(msg_pqid == 0) { 
     /* The child sends the message */ 
} else { 
    /* Parent receives the message */ 
}

I prefer to use a switch like so:

switch ((msg_pqid = fork())) {
case -1: 
    /* Error */
case 0:
    /* Child sends message */
default:
    /* Parent receives message */
}

Upvotes: 2

Related Questions