Home > Software design >  Simple multithreading in C
Simple multithreading in C

Time:12-05

I try to implement a function which prints each thread number . For example thread 0 prints 0 thread 1 prints 1 and so on , but not in this expected order.

What I have been trying so far is this

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *foo(void *arg){
    int *myid = (int*) arg;
    printf("Hello from thread %d\n",*myid);
    return NULL;
}
int main(void){
   pthread_t tid[4];
   int i;
   for(i=0;i<4;i  ){
       pthread_create(&tid[i],NULL,(void*) foo, &i);
  
   }
   for(i=0;i<4;i  ){
       pthread_join(tid[i],NULL);
   }
   return 0;
}

However this prints almost everytime Hello from thread 0 four times. How can I modify this code so each thread gets printed correctly?

CodePudding user response:

You're passing in the address of i to each of the threads, so they each read the current state of i (and without synchronization, so the results are unpredictable if not undefined).

Instead, you need to pass a pointer to thread-specific data (that has a lifetime at least as long as the thread). For example:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *foo(void *arg){
    int *myid = (int*) arg;
    printf("Hello from thread %d\n",*myid);
    return NULL;
}
int main(void){
   pthread_t tid[4];
   int ids[4];
   int i;
   for(i=0;i<4;i  ){
       ids[i] = i;
       pthread_create(&tid[i],NULL,(void*) foo, &ids[i]);
  
   }
   for(i=0;i<4;i  ){
       pthread_join(tid[i],NULL);
   }
   return 0;
}

CodePudding user response:

This is a classic situation where all the threads share the same data, but should not.

Here you pass &i to each thread, thus all of them refer to the same location in memory: the only one where the single variable i is stored. You need to pass a value but in the pthread API it is not easy since a pointer (void *) is expected.

A strategy is to prepare beforehand an array with a distinct element for each thread and pass the address of the nth element to the nth thread.

Another strategy is to dynamically allocate a new piece of information (an int here) at each iteration of the loop, initialise it (with a counter for example) and pass this address to the thread. Then the thread will have to free() its own piece of information before it leaves. This strategy is more heavyweight than the previous.

Note that sometimes we see in code an ugly shortcut, just to pass a single int. At the call site you pass (void *)(intptr_t)i and in the thread you get back (int)(intptr_t)arg. The trick is that we consider the pointer as a very big integer, thus we convert back and forth. I would not recommand that for some serious code, only for a quick experiment.

  • Related