先看一段代码
- /*
- *
- *
- * 2012-11-27 09:06:45
- * Version: 0.86
- * Author:
- * Tony <tingw.liu@gmail.com>
- *
- * vim: set tabstop=8;set softtabstop=8;set cindent;set fdm=indent
- */
- #include <stdio.h>
- #include <pthread.h>
- #include <stdlib.h>
- #include <unistd.h>
- void parentthread(void)
- {
- struct tm tbuf;
- time_t tsec;
- while(1){
- localtime_r(&tsec, &tbuf);
- usleep(100);
- }
- }
- void childthread(void)
- {
- struct tm tbuf;
- time_t tsec;
- while(1){
- localtime_r(&tsec, &tbuf);
- printf("Child working ok...\n");
- sleep(1);
- }
- }
- int main(int argc, char **argv)
- {
- pthread_t id;
- pthread_attr_t thread_attr;
- int i, ret;
- pid_t child;
- pthread_attr_init(&thread_attr);
- pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
- for (i = 0; i < 20; i++){
- pthread_create(&id, NULL, (void*)parentthread, NULL);
- }
- child = fork();
- if (child == 0){
- pthread_create(&id, NULL, (void*)childthread, NULL);
- while(1){
- sleep(10);
- }
- }else if(child > 0){
- while(1){
- sleep(10);
- }
- }else{
- exit(1);
- }
- return 0;
- }
这个代码只有几十行,但足以说明问题。如果你不能看出代码有什么严重的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子进程的时候,可能会出现某一个线程已经lock了localtime_r的锁,这时候子进程继承了这个已经标记为lock的锁。这样就导致了在子进程中调用localtime_r获取锁的时候,一直被block。
所有在多进程环境下使用thread-safe函数的时候,需要避免这种问题的出现。
阅读(1424) | 评论(0) | 转发(0) |