Behavior on sending an integer (not from heap) as an argument to the thread

Viewed 27

I want to create threads with different index values ​​from the same function. I always send the variables to threads, from the heap. But I do not want to send from the heap, because I want to send a different variable here to know the indexes of all of them; in this case if I send from the heap, the index value may change in others without being stored yet.

#include <pthread.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>

struct Myarg{
    int index;
};

void *foo(void *arg)
{
    struct Myarg *a = (struct Myarg* ) arg;
    printf("\nfoo%d executed", a->index);
    pthread_exit(NULL);
    return NULL;
}

int main(int argc, char const *argv[])
{
    pthread_t tid[6];

    struct Myarg arg;

    for (int i = 0; i < 6; i++)
    {
        arg.index = i;
        if (pthread_create(&tid[i], NULL, foo, &arg) != 0)
        {
            printf("\nerror!");
            exit(-1);
        }
    }

    for (int i = 0; i < 6; i++)
    {
        if (pthread_join(tid[i], NULL) != 0)
        {
            printf("\nerror!");
            exit(-1);
        }
    }

    return 0;
}

Here is a couple of outputs from this code:

foo1 executed
foo2 executed
foo3 executed
foo4 executed
foo5 executed
foo5 executed

foo1 executed
foo4 executed
foo3 executed
foo5 executed
foo5 executed
foo2 executed

I share this code just to show my intention. Here is an example of the various results I expected:

foo1 executed
foo4 executed
foo3 executed
foo5 executed
foo6 executed
foo2 executed

I think I can realize this intention by taking the integer from the heap and creating six argument variables different for all of them. But I wonder exactly what happened here? Or can this aim be achieved without creating 6 different variables?

1 Answers

You're sending the address of the same struct to each of your threads. This means you have a race condition regarding what value the struct happens to contain when each thread reads it.

The simplest solution is to have an array of structs and pass a different array element to each one.

struct Myarg arg[6];

for (int i = 0; i < 6; i++)
{
    arg[i].index = i;
    if (pthread_create(&tid[i], NULL, foo, &arg[i]) != 0)
    {
        printf("\nerror!");
        exit(-1);
    }
}

Also, you're not using the heap anywhere in your code because you never call any of the malloc family of functions. All of the relevant variables are locals which (on most implementations) live on the stack.

Alternately, you can allocate a structure for each thread on the heap and pass that in:

for (int i = 0; i < 6; i++)
{
    struct Myarg *arg = malloc(sizeof(*arg));
    arg->index = i;
    if (pthread_create(&tid[i], NULL, foo, arg) != 0)
    {
        printf("\nerror!");
        exit(-1);
    }
}

And the thread will be responsible for freeing the memory:

struct Myarg *a = arg;
printf("\nfoo%d executed", a->index);
free(a);
pthread_exit(NULL);
Related