3
#define THREADS_NUMBER 10

Given a function f:

void *f(void *arg){

    pthread_mutex_lock(&mutex);
    printf("%i\n", *((int*) arg);
    pthread_mutex_unlock(&mutex);

}

I don't understand why writing this:

pthread_t threads[THREADS_NUMBER];
for(int i = 0; i < THREADS_NUMBER; i++){
    pthread_create(&threads[i], NULL, f, &i);
}
for(int i = 0; i < THREADS_NUMBER; i++){
    pthread_join(threads[i], NULL);
}

outputs this:

2 4 4 5 5 6 8 8 9 10

while writing this:

int t[10];
for(int i = 0; i < 10; i++)
    t[i] = i;
pthread_t threads[THREADS_NUMBER];
for(int i = 0; i < THREADS_NUMBER; i++){
    pthread_create(&threads[i], NULL, f, &t[i]);
}
for(int i = 0; i < THREADS_NUMBER; i++){
    pthread_join(threads[i], NULL);
}

outputs this:

0 1 4 3 5 2 6 7 9 8

(In case you didn't notice the difference it's the argument passed to the thread function f in the pthread_create call.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Axel Carré
  • 303
  • 1
  • 5
  • in first case you have only one `i` but in second case you have different `t[i]`. Also your first case has undefined behavior. – kiran Biradar Oct 11 '19 at 12:30
  • It's undefined when the thread functions runs relative to the thread that controls the thread creation, so in the first case, it's undefined what values the threads will see because `i` has probably changed by the time the thread function is running. – Jonathan Leffler Oct 11 '19 at 12:41

2 Answers2

5

Try unrolling the loops. The two cases will become as below.

first case:

pthread_create(&threads[0], NULL, f, &i);
pthread_create(&threads[1], NULL, f, &i);

…
pthread_create(&threads[9], NULL, f, &i);

Second case:

pthread_create(&threads[0], NULL, f, &t[0]);
pthread_create(&threads[0], NULL, f, &t[1]);
…
pthread_create(&threads[9], NULL, f, &t[9]);

If you have noticed, in first case you always pass &i to every thread, thus each thread will be pointing to same i and its latest content.

kiran Biradar
  • 12,700
  • 3
  • 19
  • 44
3

Because here:

int i;
...
     pthread_create(&threads[i], NULL, f, &i);

you pass a pointer to a memory address to your thread:

void *f(void *arg){

But when the thread is executed, the main thread already changes this value again! So you have to pass a copy of this value, like you did with your array, or alternatively like this:

for(int i = 0; i < THREADS_NUMBER; i++){
    int *arg = malloc(sizeof(int));
    *arg = i;
    pthread_create(&threads[i], NULL, f, arg);
}

Remember to free the value in the thread function (f) when it is no longer needed — it's necessary to avoid a memory leak because there is no other reference to the allocated space. Because of this, the solution using the array is probably better.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Ctx
  • 18,090
  • 24
  • 36
  • 51