如果不使用 pthread_join(),为什么'cout'语句从特定线程打印两次(即使它是同步的)?


#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;  
}

我已经在linux fedora 22(也在http://www.cpp.sh/)上执行了以下程序大约20次,并且在20次执行中,我发现了以下输出:-

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  

输出1到3是预期的,因为主线程没有等待子线程退出。两个线程(主线程和子线程)的执行顺序完全依赖于内核线程调度。

但是输出4很奇怪!!First thread execution被打印两次!!

现在,如果我在取消注释代码'pthread_join(th1, NULL)'或添加'pthread_exit(NULL)'后运行程序,我不会得到奇怪的输出(即First thread execution从未打印两次),即使我运行代码10000次。

我对专家的问题是:

  1. 没有pthread_join/pthread_exit在后台发生了什么,所以First thread execution已经打印了2次?

pthread_join的职责是获取特定线程的退出代码,在成功调用pthread_join后,内核将释放该特定线程的资源。如果我不在一个可接合的线程上调用pthread_join,那么它将导致资源泄漏,但是为什么上面提到奇怪的行为??

我们可能会说,这是未定义的行为,但如果有专家对此提供技术解释就太好了。

如何pthread_join/pthread_exit可以防止上述奇怪的行为?由于奇怪的行为没有出现,它在这里隐藏着什么?

提前感谢专家…

我曾在类似的情况下观察到这种双打印。当您的线程在write系统调用中等待执行其正常输出时,特别是在此堆栈中:

#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

程序被正常终止,正常终止导致输出子系统刷新所有缓冲区。stdin上的输出缓冲区还没有被标记为空闲(write系统调用还没有返回),所以它被再次写出来:

#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.

在任何情况下,连接你的线程(如果你使用c++线程,它会提醒你这样做)或同步访问输出流

主线程可能比派生线程更早结束。

主线程的结束意味着整个进程的结束,同时所有线程也会突然关闭。这可能会调用未定义的行为,因此任何事情都可能发生。

绕过这个

  • main()使用pthread_join()加入生成的线程,
  • 或者使用pthread_exit()结束主线程,它只结束主线程,不结束进程。

最新更新