多线程程序中的意外输出

Des*_*PRG 9 c multithreading pthreads

以下是使用pthreads的程序.

#include <pthread.h> // posix threads 
#include <stdio.h>
#include <stdlib.h>

/* to compile use -lpthread */

void * sample_thread(void *);

#define MAX 10

int main() 
{
  pthread_t tid; 
  pthread_attr_t attr; 
  int k;  

  pthread_attr_init(&attr); // set default attributes 
  pthread_create(&tid, &attr, sample_thread, NULL); // create new thread
  // sample_thread will run as the new thread 

  for(k=0; k<MAX; k++) { 
    printf("Hi I'am %s %d \n",__func__,k); 
  }


  //this would kill all the threads,
}

void * sample_thread(void * p)
{ 
  int k; 
  for(k=0; k<MAX; k++) { 
    printf("Hi I'am %s %d \n",__func__,k); 
  }

}
Run Code Online (Sandbox Code Playgroud)

每次运行程序时,我都期望从主线程和子线程获得不同数量的执行数(因为主线程可能在子进程之前退出).我有时会得到这个预期的输出.但是我得到了如下输出,我无法理解为什么.

Hi I'am main 0 
Hi I'am main 1 
Hi I'am main 2 
Hi I'am main 3 
Hi I'am main 4 
Hi I'am main 5 
Hi I'am main 6 
Hi I'am main 7 
Hi I'am main 8 
Hi I'am main 9 
Hi I'am sample_thread 0 
Hi I'am sample_thread 0 
Hi I'am sample_thread 1 
Hi I'am sample_thread 2 
Hi I'am sample_thread 3 
Hi I'am sample_thread 4 
Hi I'am sample_thread 4 
Hi I'am sample_thread 5 
Run Code Online (Sandbox Code Playgroud)

为什么示例线程0和4打印两次?

P.P*_*.P. 10

由于强调了@R ..在评论,这似乎是一个bug中的glibc的实现(假设你使用的是Linux -我可以重现这个在Linux上使用2.17 4.9.1 GCC编译),在exit()不确保在刷新和关闭流时,当多个线程使用stdout时,一个线程调用它时没有竞争.

flockfile手册中的以下内容清楚地表明观察到的行为不正确:

stdio函数是线程安全的.这是通过为每个FILE对象分配一个lockcount和(如果lockcount非零)一个拥有线程来实现的.对于每个库调用,这些函数一直等到FILE对象不再被另一个线程锁定,然后将其锁定,执行请求的I/O并再次解锁对象.

鉴于此,我们在此处观察到的这种特殊情况可以考虑以下选项作为解决方法(因为对错误报告没有响应).


两个线程"共享" stdout流,我认为,由于主线程的过早退出,打印出"额外"输出.

printf缓冲(in sample_thread())输出,在它清除缓冲区之前(由于\n在printfs中),主线程退出.因此,stdout当进程退出时强制刷新缓冲区.

修理,

1)你可以setbuf()main()创建线程之前调用 :

setbuf(stdout, NULL);
Run Code Online (Sandbox Code Playgroud)

缓冲stdout可言.

或者
2)调用pthread_exit()两个线程,以便在任一线程死亡时继续进程.

或者
3)pthread_join()在主线程中调用,以便主线程等待线程的完成sample_thread.

其中任何一个都可以避免这个问题.

  • @BlueMoon:我能够在Linux 3.5/glibc 2.17上重现这一点.我怀疑这是[bug 14697](https://sourceware.org/bugzilla/show_bug.cgi?id=14697)的一种表现形式; 看到我对这个问题的评论,为了解释我为什么相信这一点.IMO如果只是解释说OP的代码是正确的并且应该按原样运行,你的答案会很好,但是它可能会遇到系统中的错误,而你现有的答案是一种可能的解决方法. (2认同)