Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3890755
  • 博文数量: 93
  • 博客积分: 3189
  • 博客等级: 中校
  • 技术积分: 4229
  • 用 户 组: 普通用户
  • 注册时间: 2009-02-02 13:29
个人简介

出没于杭州和青岛的程序猿一枚,对内核略懂一二

文章分类

全部博文(93)

文章存档

2016年(2)

2015年(3)

2014年(11)

2013年(29)

2012年(16)

2011年(5)

2010年(5)

2009年(22)

分类: LINUX

2012-11-27 11:01:11

先看一段代码

点击(此处)折叠或打开

  1. /*
  2.  * 
  3.  *
  4.  * 2012-11-27 09:06:45
  5.  * Version: 0.86
  6.  *    Author:
  7.  *            Tony <tingw.liu@gmail.com>
  8.  *
  9.  * vim: set tabstop=8;set softtabstop=8;set cindent;set fdm=indent
  10.  */

  11. #include <stdio.h>
  12. #include <pthread.h>
  13. #include <stdlib.h>
  14. #include <unistd.h>

  15. void parentthread(void)
  16. {
  17.     struct tm tbuf;
  18.     time_t tsec;

  19.     while(1){
  20.         localtime_r(&tsec, &tbuf);
  21.         usleep(100);
  22.     }
  23. }

  24. void childthread(void)
  25. {
  26.     struct tm tbuf;
  27.     time_t tsec;

  28.     while(1){
  29.         localtime_r(&tsec, &tbuf);
  30.         printf("Child working ok...\n");
  31.         sleep(1);
  32.     }
  33. }
  34. int main(int argc, char **argv)
  35. {
  36.     pthread_t id;
  37.     pthread_attr_t thread_attr;
  38.     int i, ret;
  39.     pid_t child;
  40.     pthread_attr_init(&thread_attr);
  41.     pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
  42.     for (i = 0; i < 20; i++){
  43.         pthread_create(&id, NULL, (void*)parentthread, NULL);
  44.     }
  45.     child = fork();
  46.     if (child == 0){
  47.         pthread_create(&id, NULL, (void*)childthread, NULL);
  48.         while(1){
  49.             sleep(10);
  50.         }
  51.     }else if(child > 0){
  52.         while(1){
  53.             sleep(10);
  54.         }
  55.     }else{
  56.         exit(1);
  57.     }
  58.     return 0;
  59. }

这个代码只有几十行,但足以说明问题。如果你不能看出代码有什么严重的bug,那么请继续往下走。。。

编译运行结果如图:

从上面的运行结果可以看出,重启运行20次后,出现了bug

下面我们调试一下:

使用gdb对子进程进行调试,发现子进程被block在一个锁上面。Why?

Man localtime_r

Localtime_r is thread-safe function.

Localtime_r使用了锁机制来保证该函数是线程安全的,但就是这个thread-safe导致了问题的发生。而且从上面的测试可以看出,不是每次都会block住,只是偶尔会被block

Linux下父进程在fork子进程的时候,子进程会继承父进程的变量。

上面的问题出现的流程可以大体描述如下:

父进程存在线程调用localtime_r函数,那么当父进程fork子进程的时候,可能会出现某一个线程已经locklocaltime_r的锁,这时候子进程继承了这个已经标记为lock的锁。这样就导致了在子进程中调用localtime_r获取锁的时候,一直被block


所有在多进程环境下使用thread-safe函数的时候,需要避免这种问题的出现。

阅读(6656) | 评论(1) | 转发(5) |
给主人留下些什么吧!~~

C011413072012-11-28 18:57:04

http://blog.chinaunix.net/uid-7931217-id-3424683.html
系统函数,无法用pthread_atfork来解决,想到的解决方案:
将子进程的内容,封装到一个单独的二进制文件
fork()出来的子进程,执行体就是execve这个单独的二进制文件
不知道还有其他的方法没有?