2
votes

I am doing an assignment that implements the producer / consumer problem using a UNIX message queue as the data structure shared by a single producer and three consumers. The program I am creating is supposed to create a child process and the child process will in turn create three threads. The parent process is to be the producer and the three threads will be the consumers. The number of items, N, that are to be produced will be provided to the program via the command line. After spawning the child process the parent will enter an N-iteration loop. In each iteration of the loop the parent will do the following:

1) Generate a random number, R, in the range of 0-999.

2) Send a message containing R.

3) Add R to a running total of all values produced.

4) Display the string “Producer produced a R”.

5) Put the producer to sleep for 0-1 seconds using sleep(rand()%2).

After the N iterations have completed display the string "Total produced = XXXX” (where XXXX is the sum of all R values produced) and wait for the child to terminate. It is the parent’s responsibility to create and destroy the queue.

The child process will create three consumer threads, 0, 1 and 2. Each thread will enter an N/3 iteration loop. In each iteration of the loop each consumer thread will do the following:

1) Read a message containing a value, C, consumed from the queue.

2) Add C to a running total maintained by each consumer thread.

3) Display the string “Consumer thread Z consumed a C” where Z is the thread number – 0,1 or 2.

4) Put the consumer thread to sleep for 1-3 seconds using sleep((rand()%3)+1)

After N/3 iterations display the string "Total consumed by consumer thread Z = YYYY” where YYYY is the sum of all N/3 values consumed.I am receiving a segmentation fault in the last iteration of the loop and I am not sure why. Can anyone help me with this issue?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sys/sem.h>
#include <semaphore.h>

struct msgbuf {
    long mtype;
    int mnum;
};
int msqid;
unsigned long total;
pthread_mutex_t sem_id;

int init() {
    srand (time(NULL));
    msqid = msgget(IPC_PRIVATE, IPC_CREAT | 0600);
    if (msqid == -1) { perror("msgget"); return EXIT_FAILURE; }
    pthread_mutex_init(&sem_id, NULL);
    total = 0;
    return 0;
}

int producer() {
    int R = rand() % 999;
    struct msgbuf msg = {999, R};
    if(msgsnd(msqid, &msg, sizeof(msg.mnum) + 1, 0) == -1) { 
perror("msgsnd"); return -1; }
    total += R;
    return R;
}

void *consumer(int thread_num, int iteration) {
    struct msgbuf msg;
    int thread_total = 0;
    while(iteration--) {
        pthread_mutex_lock(&sem_id);
        if (msgrcv(msqid, &msg, sizeof(msg.mnum) + 1, 0, 0) == -1) 
perror("msgrcv");
        thread_total += msg.mnum;
        printf("Consumer thread %d consumed a %d\n", thread_num, msg.mnum);
        pthread_mutex_unlock(&sem_id);
    }
    printf("Total consumed by consumer thread %d = %d\n", thread_num, 
thread_total);
    sleep((rand()%3)+1);
}

int main(int argc, char *argv[]) {
    int N = argc > 1 ? atoi(argv[1]) : 10;
    if (init() != 0) return EXIT_FAILURE;

    for (int i=0;i<N;i++) {
        int R = producer();
        if(R == -1) return EXIT_FAILURE;
        printf("Producer produced a %d\n", R);
        sleep(rand()%2);
    }
    printf("Total produced = %lu\n", total);
    pthread_t thread_nums[3];
    for (int i=0; i<=4; i++) {
        int iteration = i == 0 ? N/3 + (N%3) : N/3;
        if(pthread_create(&thread_nums[i], NULL,
            consumer(i, iteration), NULL) != 0) {
                perror("pthread_create");
                return EXIT_FAILURE;
        }
    }
    for (int i=0;i<4;i++) pthread_join(thread_nums[i], NULL);
    return 0;
}
1
Where is the child process? - Barmar
your call to pthread_create is incorrect. You need to pass it a function with the prototype void* consumer(void* param);. If you want to pass multiple items to consumer (looks like you do), you'll need to put them in a struct and pass that, then cast it back from void* to your struct. Do something like pthread_create(&thread_nums[i], NULL, consumer, (void*)&myStruct); Good info on pthreads here: computing.llnl.gov/tutorials/pthreads - yano
I don't think you need to protect msgrcv() with a mutex. You don't update any global variables in the consumer, so it doesn't need the mutex. - Barmar

1 Answers

0
votes

Ok so in the main function, thread_nums has 3 "slots", where as the loop proceeding wants to go over 5 different "slots".

Also, the last loop accesses a "slot" which does not exist

Remember that an array of size [3] has only three positions. The last item is at index 2 (0,1,2), for a total of three elements.