Bill Skiadas
Bill Skiadas

Reputation: 281

Wrong thread IDs in a multithreaded C program?

I am new to multithreading in C and I had this question. I wrote the following code:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;
pthread_attr_t attr;

void* test(void *a)
{
    int i=*((int *)a);
    printf("The thread %d has started.\n",i);
    pthread_mutex_lock(&m);
    sleep(1);
    printf("The thread %d has finished.\n",i);
    pthread_mutex_unlock(&m);
    pthread_exit(NULL);

}

int main()
{
    int i=0;
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
    pthread_t thread[5];

    for (i=0;i<5;i++)
        pthread_create(&thread[i],&attr,test,&i);

    for (i=0;i<5;i++)
        pthread_join(thread[i],NULL);
    return 0;
}

Why do I get values like:

The thread 0 has started.
The thread 0 has started.
The thread 5 has started.
The thread 5 has started.
The thread 0 has started.
The thread 0 has finished.
The thread 0 has finished.
The thread 5 has finished.
The thread 5 has finished.
The thread 0 has finished.

or

The thread 1 has started.
The thread 2 has started.
The thread 5 has started.
The thread 4 has started.
The thread 0 has started.
The thread 1 has finished.
The thread 2 has finished.
The thread 5 has finished.
The thread 4 has finished.
The thread 0 has finished.

or even:

The thread 0 has started.
The thread 0 has started.
The thread 0 has started.
The thread 0 has started.
The thread 0 has started.
The thread 0 has finished.
The thread 0 has finished.
The thread 0 has finished.
The thread 0 has finished.
The thread 0 has finished.

etc, when I expected to get:

The thread 0 has started.
The thread 1 has started.
The thread 2 has started.
The thread 3 has started.
The thread 4 has started.
The thread 0 has finished.
The thread 1 has finished.
The thread 2 has finished.
The thread 3 has finished.
The thread 4 has finished.

Only when I put usleep(10) after thread_create do I get some "normal" values.

I compiled and run this code in Code::Blocks on Unix.

Upvotes: 2

Views: 107

Answers (2)

templatetypedef
templatetypedef

Reputation: 372814

Notice that you are passing in the address of i as a parameter to your threads:

pthread_create(&thread[i],&attr,test,&i);

This means that all of your threads will be reading the same variable i to determine which thread they are. That is, all five threads will look at the same variable to determine their thread number. Consequently, as the value of i increments in your for loop, all the threads will perceive their thread number changing to use the new value of i. This is why you're sometimes seeing 5 come up as the thread number, and also explains the fact that you're often skipping numbers or seeing far too many duplicates.

To fix this, you will need to give each thread their own copy of i. For example, you could do something like this:

int* myI = malloc(sizeof(int));
*myI = i;
pthread_create(&thread[i], &attr, test, myI);

And then have the threads free the pointer before terminating:

void* test(void *a)
{
    int i=*((int *)a);
    printf("The thread %d has started.\n",i);
    pthread_mutex_lock(&m);
    sleep(1);
    printf("The thread %d has finished.\n",i);
    pthread_mutex_unlock(&m);
    pthread_exit(NULL);
    free(a);
}

Alternatively, you could cast i to a void* and pass that in:

pthread_create(&thread[i],&attr,test, (void*)i);

If you do this, you would then have the threads cast their arguments directly back to int, not to int*:

void* test(void *a)
{
    int i = (int)a;
    printf("The thread %d has started.\n",i);
    pthread_mutex_lock(&m);
    sleep(1);
    printf("The thread %d has finished.\n",i);
    pthread_mutex_unlock(&m);
    pthread_exit(NULL);
}

Hope this helps!

Upvotes: 2

cnicutar
cnicutar

Reputation: 182649

You're passing the address of a variable the for is changing (i) so you're at the mercy of the scheduler. You should just pass a copy. As a cheap, not completely-kosher way:

pthread_create(&thread[i],&attr,test, (void*)i);

/* ... */

int i = (int)a;

Upvotes: 5

Related Questions