Nikolaj Nikolaj - 1 month ago 11
C Question

C Linux pthreads: sending data from one thread to antoher using message queue gives unexpected result

I am writing a program that will transfer 50 integers from one thread to another using message queue and upon receiving the integers the receiver thread will print them.

At the moment the receiver thread prints first 13 integers(0,1,2..12) but after that it just prints all 0's.

Here is my code so far:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>


//define declarations
#define SIZE 50


//structs
typedef struct msgbuf {
long mtype;
int data[SIZE];
} data_buf;


//function declarations
void *send_data();
void *receive_data();

main()
{
pthread_t thread1;
pthread_t thread2;
int ret_val_t1;
int ret_val_t2;

//create thread1
ret_val_t1 = pthread_create( &thread1, NULL, send_data, NULL);
if(ret_val_t1)
{
fprintf(stderr,"Error - pthread_create() return value: %d\n",ret_val_t1);
exit(EXIT_FAILURE);
}

//create thread2
ret_val_t2 = pthread_create( &thread2, NULL, receive_data, NULL);
if(ret_val_t2)
{
fprintf(stderr,"Error - pthread_create() return value: %d\n",ret_val_t2);
exit(EXIT_FAILURE);
}

printf("pthread_create() for thread 1 returns: %d\n",ret_val_t1);
printf("pthread_create() for thread 2 returns: %d\n",ret_val_t2);

//wait untill threads are done with their routines before continuing with main thread
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);

exit(EXIT_SUCCESS);
}

void *send_data(){

int msqid;
int msgflg = IPC_CREAT | 0666;
key_t key;
data_buf sbuf;
size_t buf_length;

//get the message queue id for the key with value 1234
key = 1234;

(void) fprintf(stderr, "\nmsgget: Calling msgget(%#lx,\%#o)\n", key, msgflg);

if ((msqid = msgget(key, msgflg )) < 0) {
perror("msgget");
exit(1);
}
else{
(void) fprintf(stderr,"msgget: msgget succeeded: msqid = %d\n", msqid);
}

//send message type 1
sbuf.mtype = 1;

(void) fprintf(stderr,"msgget: msgget succeeded: msqid = %d\n", msqid);

//fill the array that is to be sent from thread1 to thread2
int i = 0;
for(i = 0; i < SIZE; i++){
sbuf.data[i] = i;
}

(void) fprintf(stderr,"msgget: msgget succeeded: msqid = %d\n", msqid);

buf_length = SIZE;

//send data from thread1 to thread2
if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0) {
perror("msgsnd");
exit(1);
}

else
printf("Data sent\n");
}

void *receive_data(){
int msqid;
key_t key;
data_buf rbuf;

//get the message queue id for the key with value 1234
key = 1234;

if ((msqid = msgget(key, 0666)) < 0) {
perror("msgget");
exit(1);
}

//receive the answer with message type 1
if (msgrcv(msqid, &rbuf, SIZE, 1, 0) < 0) {
perror("msgrcv");
exit(1);
}


//print received answer
int j = 0;
for(j = 0; j < SIZE; j++){
printf("%d\n", rbuf.data[j]);
}

}


And here is my output:

msgget: Calling msgget(0x4d2,01666)
pthread_create() for thread 1 returns: 0
pthread_create() for thread 2 returns: 0
msgget: msgget succeeded: msqid = 0
msgget: msgget succeeded: msqid = 0
msgget: msgget succeeded: msqid = 0
Data sent
0
1
2
3
4
5
6
7
8
9
10
11
12
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

Answer

This

buf_length = SIZE;

sets the message text size to 50 bytes.

Yet the structure is defined as

typedef struct msgbuf {
         long    mtype;
         int    data[SIZE];
} data_buf;

data is 50 int elements. That's not 50 bytes - it's almost certainly 200 bytes, with a 4-byte/32-bit int.

And 50 bytes is enough to hold 12 1/2 4-byte int values, explaining why you see a count up to 12.

Replace buf_length = SIZE with buf_length = sizeof( data_buf );