Why can't I pass my "for" index directly to a pthread_create call?

Viewed 54
#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.)

2 Answers

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.

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.

Related