多线程程序中的意外输出

时间:2014-10-06 07:14:15

标签: 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); 
  }

}

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

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 

为什么样本线程0和4打印两次?

1 个答案:

答案 0 :(得分:10)

正如@R ..在评论中强调的那样,在glibc的实现中似乎是a bug(假设您使用的是Linux - 我可以在使用GCC 4.9.1编译的Linux 2.17上重现这一点) ,exit()无法确保,当刷新和关闭流时,当多个线程使用stdout时,一个线程调用它时没有竞争。

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

  

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

鉴于此,我们在此处观察到的特定情况下,可以将以下选项视为一种解决方法(因为对错误报告没有响应)。


两个线程“共享”stdout流,我认为,由于主线程过早退出,会打印“额外”输出。

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

要修复,

1)在创建主题之前,您可以在setbuf()中调用main()

setbuf(stdout, NULL);

而不是缓冲区stdout

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

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

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