"something not a structure or union" - c

So i keep geting an error
request for member ‘iArray’ in something not a structure or union
int place = q.iArray[q.in];//reorder
I have another function and this call works perfect but for some reason in my consumer fucntion it producers this call...
my cdoe is:
typedef struct _struct_x
{
int iArray[MAX_COUNT];
int in;
int out;
} struct_x;
struct_x q;
void * consumer (void *t)
{
int tid = * (int *)t;
printf ("consumer started\n");
while (!done)
{
printf("IM IN THIS LOOP\n");
int q = rand() % 1000 + 1;
pthread_mutex_lock (&count_mutex);
usleep(q*1000);
if (count <= 0)
{
//its empty..
}
else{
int place = q.iArray[q.in];//reorder
q.in = (q.in+1)%MAX_COUNT;
int facto = 0;
printf("Consumer removed %d, computed %d != &d, queue size = %d\n",place,place,facto,count);
count--;
}
pthread_mutex_unlock (&count_mutex);
}
printf ("T2[%d] thread done.\n", tid);
pthread_exit (NULL);
}
I guess my main question is what causes such an error

You have redefined q as an integer in this line -
int q = rand() % 1000 + 1;
That is causing the compilation error.

Related

Use mutex cause deadlock in c

Im trying to make a mini threads game, should be a manager thread that create amount of thread as the user want, and for every round (the user choose the amount of rounds) the threads need to random number, and after all the threads finished to random number the managerGame thread should print the thread that random the greatest number and add point to this thread.
At the end of the game the ManagerGame thread should print who is the winner.
Now i wrote the next code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
struct Player{
int isFinished;
int id;
int number;
};
struct GameManager{
struct Player *Players;
int *WinnersTable;
int Rounds;
};
struct GameDetails{
int PlayersCount;
int RoundsCount;
};
struct GameManager game_manager;
pthread_mutex_t lock;
pthread_cond_t cond;
int IsGameActive;
void* ManagerGameFunc(void* gameDetails);
void* PlayerFunc(void* playerDetails);
void SetWinnerToRound(int roundNumber, int playersCount);
void StartNewRound(int playersCount);
void printWinnerToGame(int playersCount);
int IsRoundEnded(int playersCount);
int main(){
srand(time(NULL));
pthread_t ManagerThread;
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
struct GameDetails gameDetails;
printf("----GAME----\n");
printf("Enter amount of players\n");
fflush(stdin);
scanf("%d\n", &gameDetails.PlayersCount);
printf("Enter amount of rounds\n");
fflush(stdin);
scanf("%d\n", &gameDetails.RoundsCount);
printf("----GAME STARTED----\n");
pthread_create(&ManagerThread, NULL, ManagerGameFunc, &gameDetails);
pthread_join(ManagerThread, NULL);
printf("Game finished\n");
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
}
void* ManagerGameFunc(void* gameDetails){
struct GameDetails game_details = *((struct GameDetails *)gameDetails);
pthread_t *threads = (pthread_t *)malloc(game_details.PlayersCount * sizeof(pthread_t));
game_manager.Players = (struct Player *)malloc(game_details.PlayersCount * sizeof(struct Player));
game_manager.WinnersTable = (int *)malloc(game_details.PlayersCount * sizeof(int));
game_manager.Rounds = game_details.RoundsCount;
IsGameActive = 1;
for(int i = 0; i < game_details.PlayersCount; i++){
game_manager.Players[i].isFinished = 0;
game_manager.Players[i].id = i;
pthread_create(&threads[i], NULL, PlayerFunc, &game_manager.Players[i]);
}
for(int i = 0; i < game_manager.Rounds; i++){
pthread_mutex_lock(&lock);
while(!IsRoundEnded(game_details.PlayersCount)){
pthread_cond_wait(&cond, &lock);
}
SetWinnerToRound(i + 1, game_details.PlayersCount);
StartNewRound(game_details.PlayersCount);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
IsGameActive = 0;
printf("\nGame end ! The winner of the game is ...\n");
printWinnerToGame(game_details.PlayersCount);
}
void* PlayerFunc(void* playerDetails){
struct Player player = *((struct Player *)playerDetails);
while(IsGameActive){
pthread_mutex_lock(&lock);
while(player.isFinished){
pthread_cond_wait(&cond, &lock);
}
player.number = (rand() % (100 - 1 + 1)) + 1;
printf("%d", player.number);
player.isFinished = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
}
void SetWinnerToRound(int roundNumber, int playersCount){
int max = game_manager.Players[0].number;
int id = 0;
for(int i = 1; i < playersCount; i++){
if(game_manager.Players[i].number > max){
max = game_manager.Players[i].number;
id = i;
}
}
printf("--Round %d: winner is player number %d--\n", roundNumber, id + 1);
game_manager.WinnersTable[id]++;
}
void StartNewRound(int playersCount){
for(int i = 1; i < playersCount; i++){
game_manager.Players[i].isFinished = 0;
}
}
void printWinnerToGame(int playersCount){
int max = game_manager.Players[0].number;
int id = 0;
for(int i = 1; i < playersCount; i++){
if(game_manager.Players[i].number > max){
max = game_manager.Players[i].number;
id = i;
}
}
printf("Player number %d is the winner of the game !!\n", id + 1);
}
int IsRoundEnded(int playersCount){
for(int i = 0; i < playersCount; i++)
if(!game_manager.Players[i].isFinished)
return 0;
return 1;
}
But the problem is that when i run it the output is
the image is in the link
and the terminal is stuck like it show in the image.
I think that maybe the threads is in deadlock mode, isnt it?
Thank you for your help!
UPDATE
So I heard to #n.m. and to #pilcrow, and in PlayerFunc i changed the Player object to pointer to the argument cause before the change the function made a copy of the argument and every time i tried to change something in the object it didnt change in the PlayerThread. In addition i changed the pthread_cond_signal to pthread_cond_broadcast and now it work. Thank you all!
void* PlayerFunc(void* playerDetails){
struct Player player = *((struct Player *)playerDetails);
....
PlayerFunc creates a copy of its argument representing that thread/player's state. ManagerGameFunc will never see modifications to that copy, in particular whether it isFinished or not.
All your threads follow the same pattern:
pthread_mutex_lock(&lock);
while(!predicate(....)){
pthread_cond_wait(&cond, &lock);
}
....
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
First time through the loop all predicates are false. All threads therefore peacefully sleep in pthread_cond_wait. It is never signalled, because neither thread has a chance to progress and signal it. So they wait forever.

Mutex lock does not work as expected in C

I try to implement a Hospital Simulation Project with threads but the mutex lock does not work as expected registration size should not be lower than zero if registration size is equal to zero then threads must wait for increment but if I increment the number of patients (they are also threads) registration size can be lower than 0. Why is that happening?
int REGISTRATION_SIZE = 10;
pthread_cond_t condRegister;
pthread_mutex_t mutex;
Patient:
struct Patient {
struct Disease disease;
pthread_t thread_id;
int thread_num;
int Hunger_Meter; // Initialized between 1 and 100 at creation.
int Restroom_Meter; // Initialized between 1 and 100 at creation.
};
Thread function:
void *thread_func(void *p){
struct Patient *patient = (struct Patient*)p;
registration();
return NULL;
}
Sleep method:
void sleepForMs(int ms){
usleep( 1000 * ms);
}
Thread Usage:
void registration(struct Patient *p){
int rnd_wait_time;
pthread_mutex_lock(&registration_mutex);
while(REGISTRATION_SIZE == 0){
rnd_wait_time = generate_rnd_numb(WAIT_TIME) + 1;
//printf("Patient[%d] waiting for an availabe desk.\n",p->thread_num);
sleepForMs(rnd_wait_time);
increase_meters(p);
checkForRestOrCafe(p);
pthread_cond_wait(&register_cond,&registration_mutex);
}
REGISTRATION_SIZE--;
printf(" Registration size: %d \n", REGISTRATION_SIZE);
pthread_mutex_unlock(&registration_mutex);
int register_time = generate_rnd_numb(REGISTRATION_TIME) + 1;
sleepForMs(register_time);
pthread_mutex_lock(&registration_mutex);
REGISTRATION_SIZE++;
pthread_mutex_unlock(&registration_mutex);
pthread_cond_signal(&register_cond);
}
Main:
int main()
{
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&condRegister, NULL);
srand(time(NULL));
int NUMB_OF_PATIENT = 3000;
struct Disease *diseases = malloc(sizeof(struct Disease));
diseases = create_diseases();
struct Patient patient[NUMB_OF_PATIENT];
create_patients(patient,NUMB_OF_PATIENT,diseases);
for (int i = 0; i < NUMB_OF_PATIENT; i++)
{
pthread_create(&(patient[i].thread_id), NULL, thread_func, (void *)(patient + i));
}
//wait for all threads
for (int i = 0; i < NUMB_OF_PATIENT; i++)
{
pthread_join(patient[i].thread_id, NULL);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&condRegister);
return (0);
}
Divide Registration into functions:
void wait_for_available_resource(struct Patient *p, pthread_mutex_t mutex, pthread_cond_t cond, int resource){
int rnd_wait_time;
pthread_mutex_lock(&mutex);
while(resource == 0){
rnd_wait_time = generate_rnd_numb(WAIT_TIME) + 1;
sleepForMs(rnd_wait_time);
increase_meters(p);
checkForRestOrCafe(p);
pthread_cond_wait(&cond,&mutex);
}
resource--;
printf(" Resource Number: %d \n", resource);
pthread_mutex_unlock(&mutex);
}
void spend_process_time(int needed_time){
int elapsed_time = generate_rnd_numb(needed_time) + 1;
sleepForMs(elapsed_time);
}
void release_resource(pthread_mutex_t mutex, int resource_number, pthread_cond_t cond){
pthread_mutex_lock(&mutex);
printf("-----------\n");
printf("resource number:%d\n",resource_number);
resource_number++;
printf("resource number:%d\n",resource_number);
HOSPITAL_WALLET += REGISTRATION_COST;
printf("-----------\n");
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
void registration(struct Patient *p){
wait_for_available_resource(p,registration_mutex,register_cond,REGISTRATION_SIZE);
spend_process_time(REGISTRATION_TIME);
release_resource(registration_mutex,REGISTRATION_SIZE,register_cond);
}

Segmentation fault: core dumped during execution of multi-threaded program

I have realized that my code was too lengthy and rather hard to read.
Can you check over the way I pass in the arguments and constructing the arguments in the main body?
Essentially, provided that I have correct implementation of "produce" and "consume" functions, I want to pass in a shared circular queue and semaphores and mutexes to each produce/consume threads.
typedef struct circularQueue
{
int *items;
int *head;
int *tail;
int numProduced;
int numConsumed;
} circularQueue;
typedef struct threadArg
{
int id;
circularQueue *queue;
pthread_mutex_t *mutex;
sem_t *spaces;
sem_t *itemAvail;
int numItems;
int bufferSize;
int numProducer;
int numConsumer;
} threadArg;
pthread_t *producerThd;
pthread_t *consumerThd;
int main(int argc, char* argv[])
{
pthread_attr_t attr;
// In fo to pass to thread arg
circularQueue *myQueue;
pthread_mutex_t useSharedMem;
sem_t spaces;
sem_t itemAvail;
int numItems;
int bufferSize;
int numProducer;
int numConsumer;
int i, j, k, l;
if(argc != 5)
{
printf("Enter in 4 arguments - N B P C\n");
return -1;
}
numItems = atoi(argv[1]);
bufferSize = atoi(argv[2]);
numProducer = atoi(argv[3]);
numConsumer = atoi(argv[4]);
if(numItems == 0 || bufferSize == 0 || numProducer == 0 || numConsumer == 0)
{
printf("Parameters should not be 0\n");
return -1;
}
// Initialize list of threads
producerThd = malloc(sizeof(pthread_t) * numProducer);
consumerThd = malloc(sizeof(pthread_t) * numConsumer);
// Initialize semaphores
sem_init(&spaces, 0, bufferSize);
sem_init(&itemAvail, 0, 0);
// Initialize mutex
pthread_mutex_init(&useSharedMem, NULL);
// Initialzie thread attributes
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Initialize queue
myQueue = (circularQueue*)malloc(sizeof(circularQueue));
myQueue->items = (int*)malloc(sizeof(int)*bufferSize);
myQueue->head = myQueue->items;
myQueue->tail = myQueue->items;
myQueue->numProduced = 0;
myQueue->numConsumed = 0;
// thread arguments
for(i = 0; i < numProducer; i++)
{
// Initialize thraed args
threadArg *args = (threadArg*)malloc(sizeof(threadArg));
args->queue = (circularQueue*)malloc(sizeof(circularQueue));
args->mutex = &useSharedMem;
args->spaces = &spaces;
args->itemAvail = &itemAvail;
args->numItems = numItems;
args->bufferSize = bufferSize;
args->numProducer = numProducer;
args->numConsumer = numConsumer;
args->id = i;
pthread_t thisThread = *(producerThd + i);
pthread_create(&thisThread, &attr, produce, args);
}
for(j = 0; j < numConsumer; j++)
{
// Initialize thraed args
threadArg *args = (threadArg*)malloc(sizeof(threadArg));
args->queue = (circularQueue*)malloc(sizeof(circularQueue));
args->mutex = &useSharedMem;
args->spaces = &spaces;
args->itemAvail = &itemAvail;
args->numItems = numItems;
args->bufferSize = bufferSize;
args->numProducer = numProducer;
args->numConsumer = numConsumer;
args->id = j;
pthread_t thisThread = *(consumerThd + i);
pthread_create(&thisThread, &attr, consume, args);
}
for(k = 0; k < numProducer; k++)
{
pthread_join(*(producerThd+k), NULL);
}
printf("Finished waiting for producers\n");
for(l = 0; l < numConsumer; l++)
{
pthread_join(*(consumerThd+l), NULL);
}
printf("Finished waiting for consumers\n");
free(producerThd);
free(consumerThd);
free(myQueue->items);
free(myQueue);
sem_destroy(&spaces);
sem_destroy(&itemAvail);
fflush(stdout);
return 0;
}
Thank you
There are multiple sources of undefined behavior in your code, you are either compiling without enabling compilation warnings, or what I consider worst you ignore them.
You have the wrong printf() specifier in
printf("cid %d found this item %d as valid item %d\n", myArgs->id, thisItem, validItem);
because validItem is a double, so the last specifier should be %f.
Your thread functions never return a value, but you declare them to return void * which is the signature required for such functions.
You are freeing and dereferencing myQueue in the main() function but you have not initialized it because that code is commented.
Your code is also too hard to read because you have no consistent style and you mix declarations with statements, which make everything very confusing, e.g. determining the scope of a variable is very difficult.
Fixing the code will not only help others read it, but will also help you fix it and find issues quickly.

C programming Segmentation fault: 11 Thread issues

Why does this error occur when I run my code?
error: RUN FINISHED; Segmentation fault: 11; real time: 3s; user: 0ms; system: 0m
I'm creating 10 threads where each thread is a ticket seller. There is a 10by10 array that holds the seats of the tickets. Depending on the type of the ticket-seller a person will be sold that specific seat.
Is the issue with the pthreads?
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/*
* File: ticketsellers.c
* Author: iantheflyinghawaiian
*
* Created on July 4, 2016, 11:27 AM
*/
#include <stdio.h>
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// seller thread to serve one time slice (1 minute)
int theatre[10][10] ;
struct node
{
int info;
struct node *ptr;
}*front,*rear,*temp,*front1;
int count = 0;
/* Create an empty queue */
void create()
{
front = rear = NULL;
}
/* Returns queue size */
void queuesize()
{
printf("\n Queue size : %d", count);
}
/* Enqueing the queue */
void enq(int data)
{
if (rear == NULL)
{
rear = (struct node *)malloc(1*sizeof(struct node));
rear->ptr = NULL;
rear->info = data;
front = rear;
}
else
{
temp=(struct node *)malloc(1*sizeof(struct node));
rear->ptr = temp;
temp->info = data;
temp->ptr = NULL;
rear = temp;
}
count++;
}
/* Displaying the queue elements */
void display()
{
front1 = front;
if ((front1 == NULL) && (rear == NULL))
{
printf("Queue is empty");
return;
}
while (front1 != rear)
{
printf("%d ", front1->info);
front1 = front1->ptr;
}
if (front1 == rear)
printf("%d", front1->info);
}
/* Dequeing the queue */
void deq()
{
front1 = front;
if (front1 == NULL)
{
printf("\n Error: Trying to display elements from empty queue");
return;
}
else
if (front1->ptr != NULL)
{
front1 = front1->ptr;
printf("\n Dequed value : %d", front->info);
free(front);
front = front1;
}
else
{
printf("\n Dequed value : %d", front->info);
free(front);
front = NULL;
rear = NULL;
}
count--;
}
/* Returns the front element of queue */
int frontelement()
{
if ((front != NULL) && (rear != NULL))
return(front->info);
else
return 0;
}
/* Display if queue is empty or not */
void empty()
{
if ((front == NULL) && (rear == NULL))
printf("\n Queue empty");
else
printf("Queue not empty");
}
//Ticket Seller
void * sell(char *seller_type)
{
char seller_type1;
seller_type1 = *seller_type;
int i;
i = 0;
while (i == 0);
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
// Serve any buyer available in this seller queue that is ready
// now to buy ticket till done with all relevant buyers in their queue
//………………
// Case statements for seller_types
switch(seller_type1)
{
case 'H' :
printf("Seller type: H\n");
i = 1;
break;
case 'M' :
printf("Seller type: M\n");
i = 1;
break;
case 'L' :
printf("Seller type: L\n");
i = 1;
break;
}
}
return NULL; // thread exits
}
void wakeup_all_seller_threads()
{
pthread_mutex_lock(&mutex);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
}
int main()
{
int i, N;
pthread_t tids[10];
printf("Enter N value of Customers: ");
scanf("%d", &N);
printf("Number of Customers: %d", N);
char seller_type;
// Create necessary data structures for the simulator.
// Create buyers list for each seller ticket queue based on the
// N value within an hour and have them in the seller queue.
// Create 10 threads representing the 10 sellers.
seller_type = 'H';
pthread_create(&tids[i], NULL, sell, &seller_type);
seller_type = 'M';
for (i = 1; i < 4; i++)
pthread_create(&tids[i], NULL, sell, &seller_type);
seller_type = 'L';
for (i = 4; i < 10; i++)
pthread_create(&tids[i], NULL, sell, &seller_type);
// wakeup all seller threads
wakeup_all_seller_threads();
// wait for all seller threads to exit
for (i = 0 ; i < 10 ; i++)
pthread_join(&tids[i], NULL);
// Printout simulation results
//…………
exit(0);
}
As already assumed by #2501: the culprit causing the segfault was the uninitialized variable i in main.
I took the liberty to write a minimal example for your pthread-creating, with the addition of some printf`s.
It compiles without warnings with
gcc -W -Wall threadtest.c -o threadtest -pthread
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
struct seller_type {
char st;
int tid;
};
void *sell(void *arg)
{
struct seller_type *seller_type1 = arg;
int i;
i = 0;
printf("thread #%d: seller_type1->st = %c\n", seller_type1->tid,
seller_type1->st);
// no semicolon after while()
while (i == 0) {
switch (seller_type1->st) {
case 'H':
printf("Seller type: H\n");
i = 1;
break;
case 'M':
printf("Seller type: M\n");
i = 1;
break;
case 'L':
printf("Seller type: L\n");
i = 1;
break;
}
}
printf("thread #%d: Work done\n", seller_type1->tid);
return NULL;
}
int main()
{
int i = 0;
struct seller_type *seller_type1;
pthread_t tids[10];
seller_type1 = calloc(10, sizeof(struct seller_type));
// All error handling ommitted! Yes, ALL!
seller_type1[0].st = 'H';
seller_type1[0].tid = 0;
pthread_create(&tids[0], NULL, sell, &seller_type1[0]);
for (i = 1; i < 4; i++) {
seller_type1[i].st = 'M';
seller_type1[i].tid = i;
pthread_create(&tids[i], NULL, sell, &seller_type1[i]);
}
for (i = 4; i < 10; i++) {
seller_type1[i].st = 'L';
seller_type1[i].tid = i;
pthread_create(&tids[i], NULL, sell, &seller_type1[i]);
}
puts("All threads created");
// wait for all seller threads to exit
for (i = 0; i < 10; i++) {
pthread_join(tids[i], NULL);
printf("Thread %d joined\n", i);
}
puts("All threads joined");
exit(EXIT_SUCCESS);
}
I hope you can build upon that.
You have a data race when you pass seller_type to the newly created thread, while at the same time modify the variable in the main.
The type of the function passed to pthread_create must be: void*(*)(void*), not the type you're using.
Function pthread_join requires a type pthread_t as the first argument, not a pointer to that type, which is what you're passing to it.
The variable i in the main isn't initialized, and is used to index the array tids, in the first pthread_create call.
All of those four problems cause undefined behavior by themselves. I suspect the last one causes the crash.

Where is my message queue producing a segmentation fault?

The message queue simply stops working when dealing with many many threads. It only seems to work okay with 10 threads, for exmaple. GDB tells me
Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=endptr#entry=0x0, base=base#entry=10, group=group#entry=0, loc=0x7ffff78b0060 <_nl_global_locale>)
at ../stdlib/strtol_l.c:298
298 ../stdlib/strtol_l.c: No such file or directory.
But I have no idea what this means. The same code on Windows works fine but on linux it doesn't, which confuses me more.
You can see below how this queue works. It is a singly linked list with locking while receiving messages. Please help me find where I messed up.
typedef struct Message {
unsigned type;
unsigned code;
void *data;
} Message;
typedef struct MessageQueueElement {
Message message;
struct MessageQueueElement *next;
} MessageQueueElement;
typedef struct MessageQueue {
MessageQueueElement *first;
MessageQueueElement *last;
} MessageQueue;
MessageQueue mq;
pthread_mutex_t emptyLock, sendLock;
pthread_cond_t emptyCond;
void init() {
mq.first = malloc(sizeof(MessageQueueElement));
mq.last = mq.first;
pthread_mutex_init(&emptyLock, NULL);
pthread_mutex_init(&sendLock, NULL);
pthread_cond_init(&emptyCond, NULL);
}
void clean() {
free(mq.first);
pthread_mutex_destroy(&emptyLock);
pthread_mutex_destroy(&sendLock);
pthread_cond_destroy(&emptyCond);
}
void sendMessage(MessageQueue *this, Message *message) {
pthread_mutex_lock(&sendLock);
if (this->first == this->last) {
pthread_mutex_lock(&emptyLock);
this->last->message = *message;
this->last = this->last->next = malloc(sizeof(MessageQueueElement));
pthread_cond_signal(&emptyCond);
pthread_mutex_unlock(&emptyLock);
} else {
this->last->message = *message;
this->last = this->last->next = malloc(sizeof(MessageQueueElement));
}
pthread_mutex_unlock(&sendLock);
}
int waitMessage(MessageQueue *this, int (*readMessage)(unsigned, unsigned, void *)) {
pthread_mutex_lock(&emptyLock);
if (this->first == this->last) {
pthread_cond_wait(&emptyCond, &emptyLock);
}
pthread_mutex_unlock(&emptyLock);
int n = readMessage(this->first->message.type, this->first->message.code, this->first->message.data);
MessageQueueElement *temp = this->first;
this->first = this->first->next;
free(temp);
return n;
}
some test code:
#define EXIT_MESSAGE 0
#define THREAD_MESSAGE 1
#define JUST_A_MESSAGE 2
#define EXIT 0
#define CONTINUE 1
int readMessage(unsigned type, unsigned code, void *data) {
if (type == THREAD_MESSAGE) {
printf("message from thread %d: %s\n", code, (char *)data);
free(data);
} else if (type == JUST_A_MESSAGE) {
puts((char *)data);
free(data);
} else if (type == EXIT_MESSAGE) {
puts("ending the program");
return EXIT;
}
return CONTINUE;
}
int nThreads;
int counter = 0;
void *worker(void *p) {
double pi = 0.0;
for (int i = 0; i < 1000000; i += 1) {
pi += (4.0 / (8.0 * i + 1.0) - 2.0 / (8.0 * i + 4.0) - 1.0 / (8.0 * i + 5.0) - 1.0 / (8.0 * i + 6.0)) / pow(16.0, i);
}
char *s = malloc(100);
sprintf(s, "pi equals %.8f", pi);
sendMessage(&mq, &(Message){.type = THREAD_MESSAGE, .code = (int)(intptr_t)p, .data = s});
counter += 1;
char *s2 = malloc(100);
sprintf(s2, "received %d message%s", counter, counter == 1 ? "" : "s");
sendMessage(&mq, &(Message){.type = JUST_A_MESSAGE, .data = s2});
if (counter == nThreads) {
sendMessage(&mq, &(Message){.type = EXIT_MESSAGE});
}
}
int main(int argc, char **argv) {
clock_t timer = clock();
init();
nThreads = atoi(argv[1]);
pthread_t threads[nThreads];
for (int i = 0; i < nThreads; i += 1) {
pthread_create(&threads[i], NULL, worker, (void *)(intptr_t)i);
}
while (waitMessage(&mq, readMessage));
for (int i = 0; i < nThreads; i += 1) {
pthread_join(threads[i], NULL);
}
clean();
timer = clock() - timer;
printf("%.2f\n", (double)timer / CLOCKS_PER_SEC);
return 0;
}
--- EDIT ---
Okay I managed to fix the problem by changing the program a bit using semaphores. The waitMessage function doesn't have to be locked since it is accessed by only one thread and the values that it modifies does not clash with sendMessage.
MessageQueue mq;
pthread_mutex_t mutex;
sem_t sem;
void init() {
mq.first = malloc(sizeof(MessageQueueElement));
mq.last = mq.first;
pthread_mutex_init(&mutex, NULL);
sem_init(&sem, 0, 0);
}
void clean() {
free(mq.first);
pthread_mutex_destroy(&mutex);
sem_destroy(&sem);
}
void sendMessage(MessageQueue *this, Message *message) {
pthread_mutex_lock(&mutex);
this->last->message = *message;
this->last = this->last->next = malloc(sizeof(MessageQueueElement));
pthread_mutex_unlock(&mutex);
sem_post(&sem);
}
int waitMessage(MessageQueue *this, int (*readMessage)(unsigned, unsigned, void *)) {
sem_wait(&sem);
int n = readMessage(this->first->message.type, this->first->message.code, this->first->message.data);
MessageQueueElement *temp = this->first;
this->first = this->first->next;
free(temp);
return n;
}
Your waitMessage function is modifying this->first outside of any locking. This is a bad thing.
It's often not worth recreating things that are already provided for you by an OS. You're effectively trying to set up a pipe of Message structures. You could simply use an anonymous pipe instead (see here for Linux, or here for Windows) and write/read Message structures to/from it. There's also POSIX message queues which are probably a bit more efficient.
In your case with multiple worker threads you'd have to have a supplementary mutex semaphore to control which worker is trying to read from the pipe or message queue.

Resources