简体   繁体   中英

why the main function can't pass the correct argument to the pthread_creat function

I am trying to solve the philosopher problem by limitating the number of the philosophers who are eating at 4. And in the main function, I code like this to create the threads.

for (i = 0; i < N; i++) {
        pthread_create(&tidp[i], NULL, creatPhilosopher, (void *)&i);
    }

but here are the output

philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is thinking...
philosopher 0 is eating...
philosopher 0 is eating...
philosopher 0 is eating...
philosopher 0 is eating...
philosopher 0 is eating...

while, I tried another way like this

 for (i = 0; i < N; i++) {
        int* temp = (int*)malloc(sizeof(int));
        *temp = i;
        pthread_create(&tidp[i], NULL, creatPhilosopher, (void *)temp);
    }

and the output is correct.

philosopher 4 is thinking...
philosopher 3 is thinking...
philosopher 2 is thinking...
philosopher 1 is thinking...
philosopher 0 is thinking...
philosopher 4 is eating...
philosopher 3 is eating...
philosopher 2 is eating...
philosopher 1 is eating...
philosopher 0 is eating...
philosopher 4 is thinking...
philosopher 3 is thinking...
philosopher 2 is thinking...
philosopher 1 is thinking...

So, what's the difference between the two ways?

In the first case you have only one single memory location that is passed to all the different threads: the address of variable i . So all threads will read their number from the same place. What they read from there depends on when they read that value. It seems a bit odd that all read 0, but in any case, this is not what you want.

In the second case you give each thread a different memory location. So each thread reads from a different location and thus a different number.

In the first example, you pass a pointer/reference/handle to the same variable, for every thread. One variable holds one value. You're also not synchronising accesses to that variable (not to mention it could be destroyed before every thread is done trying to read from it), so really all bets are off.

In the second example, each thread gets a copy of i with the correct value, and since the variables are independent objects you also have thread-safety.

You should always be thinking about object lifetime, ownership and access patterns.

The difference is undefined behavior.

for (i = 0; i < N; i++) {
     pthread_create(&tidp[i], NULL, creatPhilosopher, (void *)&i);
}

Neither the C++ standard, nor POSIX, whose thread API you are using, gives you any guarantee, whatsoever, that createPhilosopher will start executing and read the value of the pointer that gets passed to it before the for loop's iteration finishes, so that the new thread reads the current value of i . There is no guarantee that createPhilosopher actually starts executing before pthread_create returns in the main execution thread. It may, or may not. It depends on the phase the moon, and the tides.

And by the time the execution threads start executing, it's likely that the entire for loop has finished, and is just a distant memory. It called pthread_create some number of times (but they execution threads have not yet started executing), and, in fact, the i variable is now been destroyed and no longer exists (wherever it was declared), and its memory is now occupied by some other randomly-chosen value, or it's garbage, so by the time the new execution threads read the pointer that they receive as a parameter, it is pointing to garbage.

In the other case you're allocating a single int value in dynamic scope that still exists when the execution threads actually start executing, so they read the value. Nothing free s them, so the pointer are still value. And you leaked memory, but that's another story.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM