多线程与fork使用
如果一个多线程程序的某个线程调用了fork函数,那么新创建的子进程是否将自动创建和父进程相同数量的线程呢?
子进程仅保留调用fork的那个线程,其他线程在子进程中会被终止
原因:多线程环境下直接复制所有线程会引发严重的一致性问题,例如:
锁状态不一致:若父进程中某线程持有锁,子进程复制该线程会导致锁被永久占用,引发死锁。
资源竞争:多线程共享的全局变量、文件描述符等状态难以在子进程中正确还原。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;static void* thread_fun(void*arg)
{sleep(1);pid_t pid;pthread_mutex_lock(&mutex);pid = fork();if(pid==0){pthread_mutex_unlock(&mutex);printf(" child \r\n");}if(pid>0){pthread_mutex_unlock(&mutex);printf(" parrent \r\n");}printf(" thread_fun \r\n");
}int main()
{pthread_t tid;printf("hell test \r\n");if(pthread_create(&tid,NULL,thread_fun,NULL)){printf("create new thread failed\r\n");return -1;}pthread_mutex_lock(&mutex);sleep(2);pthread_mutex_unlock(&mutex);printf("main \r\n");if(pthread_join(tid,NULL)) // 等待子进程退出{printf("join thread failed \r\n");return -1;}return 0;
}
gcc thread_lock_fock.c -o thread_atfork -lpthread
打印只有一个hell_test 说明 子进程仅保留调用fork的那个线程,其他线程在子进程中会被终止
互斥条件:锁同一时间只能被一个线程持有,pthread_mutex_lock 多次调用未解锁,将导致死锁
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;static void* thread_fun(void*arg)
{sleep(1);pid_t pid;pid = fork();if(pid==0){pthread_mutex_lock(&mutex);printf(" child \r\n");pthread_mutex_unlock(&mutex);}if(pid>0){pthread_mutex_lock(&mutex);printf(" parent is%d\r\n",pid);pthread_mutex_unlock(&mutex);}printf(" thread_fun \r\n");
}int main()
{pthread_t tid;printf("hell test \r\n");if(pthread_create(&tid,NULL,thread_fun,NULL)){printf("create new thread failed\r\n");return -1;}pthread_mutex_lock(&mutex);sleep(2);pthread_mutex_unlock(&mutex);printf("main \r\n");if(pthread_join(tid,NULL)) // 等待子进程退出{printf("join thread failed \r\n");return -1;}return 0;
}
gcc thread_fork_lock.c -o thread_atfork -lpthread
root@camera-virtual-machine:/mnt/hgfs/E/pthread# ./thread_atfork
// 子进程没法解锁 死锁
解决使用pthread_atfork函数
#include <pthread.h>int pthread_atfork(void (*prepare)(void),void (*parent)(void),void (*child)(void));
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;// 在fork前释放锁
static void prepare(void)
{printf("Prepare: Uocking mutex before fork\n");pthread_mutex_lock(&mutex);
}// fork后父进程重新加锁
static void parent(void)
{printf("Parent: Relocking mutex after fork\n");pthread_mutex_unlock(&mutex);
}// fork后子进程重置锁状态
static void child(void)
{printf("Child: Resetting mutex after fork\n");// 子进程可能需要重新初始化锁pthread_mutex_unlock(&mutex);
}static void* thread_fun(void*arg)
{sleep(1);pid_t pid;// 注册fork处理函数pthread_atfork(prepare, parent, child);pid = fork();if(pid==0){pthread_mutex_lock(&mutex);printf(" child \r\n");pthread_mutex_unlock(&mutex);}if(pid>0){pthread_mutex_lock(&mutex);printf(" parent is%d\r\n",pid);pthread_mutex_unlock(&mutex);}printf(" thread_fun \r\n");
}int main()
{pthread_t tid;printf("hell test \r\n");if(pthread_create(&tid,NULL,thread_fun,NULL)){printf("create new thread failed\r\n");return -1;}pthread_mutex_lock(&mutex);sleep(2);pthread_mutex_unlock(&mutex);printf("main \r\n");if(pthread_join(tid,NULL)) // 等待子进程退出{printf("join thread failed \r\n");return -1;}return 0;
}
root@camera-virtual-machine:/mnt/hgfs/E/pthread# gcc thread_atfork.c -o thread_atfork -lpthread
root@camera-virtual-machine:/mnt/hgfs/E/pthread#
root@camera-virtual-machine:/mnt/hgfs/E/pthread#
root@camera-virtual-machine:/mnt/hgfs/E/pthread# ./thread_atfork
hell test
Prepare: Uocking mutex before fork
main
Parent: Relocking mutex after forkparent is3644thread_fun
Child: Resetting mutex after forkchild thread_fun