3
#include < iostream >  
#include < pthread.h >  
using namespace std;  

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* Func(void *)  
{  
    pthread_mutex_lock(&mutex);  
    cout << "First thread execution" << endl;  
    pthread_mutex_unlock(&mutex);
}

int main()  
{  
    pthread_t th1;  
    pthread_create(&th1, NULL, Func, NULL);  
    pthread_mutex_lock(&mutex);  
    cout << "In main thread" << endl;  
    pthread_mutex_lock(&mutex);  
    // pthread_join(th1, NULL); // Note this code is commented  
    return 0;  
}

I have executed following program on linux fedora 22 (also on http://www.cpp.sh/) around 20 times, and out of 20 execution I have found following outputs:-

Output1:

In main thread  
First thread execution  

Output2:

First thread execution  
In main thread  

Output3:

In main thread  

Output4:

In main thread  
First thread execution  
First thread execution  

Output 1 to 3 are expected as main thread is not waiting child thread to exit. Execution sequence of both the threads (main and child) is fully dependent on Kernel thread scheduling.

But output 4 is strange !!! First thread execution gets printed two times !!!

Now if I run program after un-commentting code 'pthread_join(th1, NULL)' or add 'pthread_exit(NULL)', I do not get strange output (i.e. First thread execution never printed twice) ever, even I run code 10000 times.

My questions to experts are:

  1. Without pthread_join/pthread_exit what is happening behind the scene so that First thread execution have got printed 2 times?

Responsibility of pthread_join is to get exit code of a particular thread, and after successful call of pthread_join, kernel will free resources of that particular thread. If I do not call pthread_join on a joinable thread then it will result in resource leak, but why above mentioned strange behavior ??

We might say, this is un-defined behavior, but it would be great if any expert provide technical explanation on this.

  1. How pthread_join/pthread_exit can prevent above mentioned strange behavior ? What hidden thing it is doing here due to that strange behavior doesn't appear ?

Thanks to experts in advance..

Abhishek
  • 33
  • 5
  • 1
    I can't reproduce this but your thread function `Func()` does not have a `return` statement which is probably giving you undefined behaviour. – Galik Aug 10 '15 at 07:58
  • 1
    You might wanna synchronize access to `std::cout` too. – Galik Aug 10 '15 at 08:05
  • possible duplicate of [Is cout synchronized/thread-safe?](http://stackoverflow.com/questions/6374264/is-cout-synchronized-thread-safe) – marcinj Aug 10 '15 at 08:06
  • 4
    possible duplicate of [pthread: one printf statement get printed twice in child thread](http://stackoverflow.com/questions/13550662/pthread-one-printf-statement-get-printed-twice-in-child-thread) – Peut22 Aug 10 '15 at 08:08
  • @Galik: After adding 'return NULL;' issue still appears. Synchronize access will print 'text' and 'endl' in proper sequence. But in the program we have only two 'cout' statements, and these two statement print 'in main thread', 'endl', 'First thread execution' and 'endl'. Without synchronization sequence of these 4 can be anything. But here in output I get addition print statement (i.e. Six things are getting printed). – Abhishek Aug 10 '15 at 08:17
  • you have not joined the thread before the program ends. Anything could happen. – Richard Hodges Aug 10 '15 at 08:19
  • I would imagine that by not calling `thred_join()` before program exit you are likely invoking undefined behaviour. – Galik Aug 10 '15 at 08:21

2 Answers2

1

I've observed this kind of double printing in a similar situation. While your thread was waiting in the write system call doing its normal output, specifically, in this stack:

#0  0x00007ffff78f4640 in write () from /lib64/libc.so.6
#1  0x00007ffff788fb93 in _IO_file_write () from /lib64/libc.so.6
#2  0x00007ffff788fa72 in new_do_write () from /lib64/libc.so.6
#3  0x00007ffff7890e05 in _IO_do_write () from /lib64/libc.so.6
#4  0x00007ffff789114f in _IO_file_overflow () from /lib64/libc.so.6

the program was terminated normally, normal termination caused the output subsystem to flush all buffers. The output buffer on stdin was not yet marked free (the write system call didn't return yet), so it was written out again:

#0  0x00007ffff78f4640 in write () from /lib64/libc.so.6
#1  0x00007ffff788fb93 in _IO_file_write () from /lib64/libc.so.6
#2  0x00007ffff788fa72 in new_do_write () from /lib64/libc.so.6
#3  0x00007ffff7890e05 in _IO_do_write () from /lib64/libc.so.6
#4  0x00007ffff7890140 in _IO_file_sync () from /lib64/libc.so.6
#5  0x00007ffff7891f56 in _IO_default_setbuf () from /lib64/libc.so.6
#6  0x00007ffff7890179 in _IO_file_setbuf () from /lib64/libc.so.6
#7  0x00007ffff7892703 in _IO_cleanup () from /lib64/libc.so.6
#8  0x00007ffff78512f8 in __run_exit_handlers () from /lib64/libc.so.

In any case, join your threads (If you used C++ threads, it would have reminded you to do that) or otherwise synchronize access to the output stream.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • Hello Cubbi, synchronize access to output stream means 'putting a mutex lock for cout statements', right ? I have put mutex lock for cout statement, but strange behavior still appears. Off course with 'pthread_join' / 'pthread_exit' strange behavior doesn't appear at all. – Abhishek Aug 10 '15 at 11:54
  • @Abhishek In this case, you could have main wait on a condition variable or a future that would be signaled by the thread after its output or at [thread exit](http://en.cppreference.com/w/cpp/thread/notify_all_at_thread_exit) – Cubbi Aug 11 '15 at 01:55
0

The main thread might end earlier then the spawned thread.

Ending the main thread implies ending the whole process, along with all threads being brought down abruptly. This might invoke undefined behaviour, thus anything can happen.

To get around this

  • either join the spawned thread using pthread_join() from main(),
  • or end the main thread using pthread_exit(), which just ends the main thread and keeps the process from being ended.
alk
  • 69,737
  • 10
  • 105
  • 255