printf在多线程应用程序中开玩笑?

时间:2012-08-18 16:42:29

标签: c pthreads printf

以下代码如何

while(1) {
  client_name_len = sizeof(struct sockaddr_in);
  newsockfd = accept(sockfd, (struct sockaddr *)&client_name, &client_name_len);
  if (newsockfd < 0) {
    perror("ERROR on accept");
    printf("Finished\n");
    close(sockfd);
    exit (EXIT_FAILURE);
  }
  printf("a:");
  pthread_t thread1;
  int *addr = (int*)malloc(sizeof(int));
  *addr = newsockfd;
  pthread_create( &thread1, NULL, &ProcessClient, (void*)addr);
}

产生以下输出:

a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:ERROR on accept: Too many open files
a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:a:Finished

问题是perror("ERROR on accept")printf("Finished\n")printf("a:")在同一个线程中执行,但输出是混合的。

ProcessClient不输出任何内容,也不创建任何线程。 sockfd是标准的侦听tcp套接字。

2 个答案:

答案 0 :(得分:2)

printf("a:");printf("Finished\n");缓存I / O转到stdout。

perror("ERROR on accept");未缓冲(或立即刷新)I / O转到stderr。

所以a:之后显示的ERROR on accept: Too many open files之前的printf()实际上是{{1}}',但缓冲会让它们稍后出现在控制台上。

有关解决问题的详细信息和方法,请参阅https://stackoverflow.com/a/3746795/12711

答案 1 :(得分:1)

正如迈克尔所指出的,第一个问题是你正在使用两个不同的流(stdout和stderr),而另一个是缓冲的,而另一个是无缓冲的。但是,您还将输出分解为多个stdio调用,这使其成为非原子的。我建议将perror替换为:

printf("ERROR on accept: %s\n", strerror_l(errno));

或切换其他printf来电fprintf使用stderr,以便您对要撰写的信息流保持一致。

然后,为了使其成为原子,请在函数开头调用flockfile(f)并在返回之前调用funlockfile(f)(其中fstdout或{替换为stderr {1}}你选择使用)。或者如果你真的想要同时使用它们,你可以锁定它们......