I'm training on C and threads. I found the following code from this page and compiled it on my Ubuntu 20.04 machine:
// C program to show thread functions
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void* func(void* arg)
{
// detach the current thread
// from the calling thread
pthread_detach(pthread_self());
usleep(3*1000000);
printf("Inside the thread\n");
// exit the current thread
pthread_exit(NULL);
}
void fun()
{
pthread_t ptid;
// Creating a new thread
pthread_create(&ptid, NULL, &func, NULL);
printf("This line may be printed"
" before thread terminates\n");
// The following line terminates
// the thread manually
// pthread_cancel(ptid);
// Compare the two threads created
if(pthread_equal(ptid, pthread_self()))
printf("Threads are equal\n");
else
printf("Threads are not equal\n");
// Waiting for the created thread to terminate
pthread_join(ptid, NULL);
printf("This line will be printed"
" after thread ends\n");
pthread_exit(NULL);
}
// Driver code
int main()
{
fun();
return 0;
}
I just added a usleep
in the thread function but the behavior doesn't change.
If I understand everything correctly the message "This line will be printed after thread ends"
shall be always printed at the very end of the program, when thread ptid is ended.
But in reality, it often happens that this ending message is printed and then after 3 seconds (due to usleep
call) it is printed the message "Inside the thread", seeming that thread ptid is still alive and running.
Without the usleep
(as per original code) happened the same just without the 3s wait in the middle.
What's going wrong?
CodePudding user response:
A spotted in the comments, the source of the main issue of your code is that you call pthread_detach
.
The later pthread_join
will just ignore the thread you detach.
At this point all thread "live their own life" which means the the only remaining synchronization mechanism is at the "exit" (when main returns). On exit, the compiler added some code that will wait for all threads to terminate.
So as threads are not synchronized in any way, what is happening is just a race condition.
When adding the usleep, you just delay the fist thread enough for the other one to have much time to finish first.
When no usleep, the race just produces random order of logs.
Worth to notice that stdout is bufferized, so the output may not be displayed at the time the printf call is done.
Remove the pthread_detach() will restore the synchro provided by pthread_join, so the log will appea in the order you expect (if I put aside the stdout bufferization pb)