【问题标题】:Why 'cout' statement printed twice (even it is synchrinized) from a particular thread if pthread_join() is not used?如果不使用 pthread_join(),为什么从特定线程打印两次“cout”语句(即使它是同步的)?
【发布时间】:2015-11-02 01:14:13
【问题描述】:
#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 次执行中我发现了以下输出:-

输出1:

In main thread  
First thread execution  

输出2:

First thread execution  
In main thread  

输出3:

In main thread  

输出4:

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 则会导致资源泄漏,但是为什么上面提到的奇怪行为呢??

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

  1. pthread_join/pthread_exit 如何防止上述奇怪行为?由于没有出现这种奇怪的行为,它在这里做了什么隐藏的事情?

提前感谢专家..

【问题讨论】:

  • 我无法重现这一点,但您的线程函数 Func() 没有 return 语句,这可能会给您带来未定义的行为。
  • 您可能还想同步访问std::cout
  • @Galik:在添加 'return NULL;' 之后问题仍然出现。 Synchronize access 将按正确的顺序打印“text”和“endl”。但是在程序中我们只有两条'cout'语句,这两条语句打印'in main thread'、'endl'、'First thread execution'和'endl'。没有这4个同步序列可以是任何东西。但是在输出中我得到了额外的打印语句(即打印了六件事)。

标签: c++ multithreading pthreads


【解决方案1】:

我在类似的情况下观察到了这种双重打印。当您的线程在 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++ 线程,它会提醒您这样做)或以其他方式同步对输出流的访问。

【讨论】:

  • 您好 Cubbi,同步访问输出流意味着“为 cout 语句设置互斥锁”,对吗?我已经为 cout 语句设置了互斥锁,但仍然出现奇怪的行为。没有出现“pthread_join”/“pthread_exit”奇怪的行为。
  • @Abhishek 在这种情况下,您可以主要等待条件变量或线程在其输出后或thread exit处发出信号的未来
【解决方案2】:

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

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

解决这个问题

  • 要么使用来自main()pthread_join() 加入派生线程,
  • 或使用pthread_exit() 结束主线程,这只是结束主线程并保持进程不被结束。

【讨论】:

    猜你喜欢
    • 2021-01-04
    • 2021-12-25
    • 1970-01-01
    • 2018-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2017-01-08
    相关资源
    最近更新 更多