hgajshb
hgajshb

Reputation: 225

Strange behavior when functions created in pthread_create accept pointer-to-int

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

void *runner(void * p)
{
    int *line = p;
    printf("line: %d\n", *line);
}
int main()
{
    pthread_t tid[2];                                                                                                       
    for (int i = 0; i < 2; i++)
        pthread_create(&tid[i], 0, runner, &i);
    for (int i = 0; i < 2; i++)                                                                                                       
        pthread_join(tid[i], NULL);
    return 0;
}

For the above code I expect the output to be

line 0
line 1

But the output is actually

line 1
line 2

So what is wrong with this code? How did i get incremented? Do I have to pass structs to the runner function?

Upvotes: 0

Views: 57

Answers (1)

Petr Skocik
Petr Skocik

Reputation: 60067

There's no guarantee that printf("line: %d\n", *line); line will finish before pthread_create returns, which means you have a race on i. (The main thread tries to increment it and the new threads try to read it via their argument pointer).

You can solve the problem by passing pointers to different objects (one per thread, optimally cache-aligned, but that hardly matters here):

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

void *runner(void * p)
{
    int *line = p;
    printf("line: %d\n", *line);
    return 0;
}
int main()
{
    pthread_t tid[2];
    int ints[2];
    for (int i = 0; i < 2; i++){
        ints[i]=i;
        if(pthread_create(&tid[i], 0, runner, &ints[i])) return 1;
    }
    for (int i = 0; i < 2; i++)
        pthread_join(tid[i], NULL);
    return 0;
}

or by passing the i by value (by casting it to void*):

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

void *runner(void * p)
{
    printf("line: %d\n", (int)(intptr_t)p);
    return 0;
}
int main()
{
    pthread_t tid[2];
    int ints[2];
    for (int i = 0; i < 2; i++){
        if(pthread_create(&tid[i], 0, runner, (void*)(intptr_t)i)) return 1;
    }
    for (int i = 0; i < 2; i++)
        pthread_join(tid[i], NULL);
    return 0;
}

Upvotes: 1

Related Questions