单线程场景
对于fork系统调用,我们知道是linux下创建子进程的一种方式。fork调用一次,对于程序看来,是“返回两次”。这里其实理解为fork调用中,已经创建出了子进程,父子进程分别分从fork调用中返回。父进程需要知道子进程的进程ID,所以返回值大于0的是父进程,而子进程返回0即可,子进程可以通过getpid获取自身进程ID和getppid获取父进程ID。
多线程场景
对于多线程场景中,例如一个10个线程的进程中。如果某个线程调用了fork,新的子进程中会有多少个线程?请思考30秒。
正确答案是:直接man fork即可看到。
Note the following further points:
The child process is created with a single thread—the one that called fork(). The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects; the use of pthread_atfork(3) may be helpful for dealing with problems that this can cause.
结论:只有当前线程会被复制到子线程中。
为什么fork只复制当前线程
试想,如果多个线程都被复制到了子进程中,除了当前线程能通过fork返回值判断,其他线程怎么感知到自己被复制到了子线程呢?从逻辑上就比较容易推断出,这种多线程同时复制到子进制的fork方案是不合理的。
锁资源
锁资源例如mutex,同样也是会被复制到子进程中。那么就会出现一种情况,当前线程的mutex的状态被复现到了子进程中。如果mutext是被加锁状态,则在子进程如果尝试对mutext进行加锁的时候,会导致子锁的产生。如下代码所示:
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *fun(void *arg)
{
printf("pid = %d begin doit ...\n", static_cast<int>(getpid()));
pthread_mutex_lock(&mutex);
struct timespec ts = {
2, 0};
nanosleep(&ts, NULL);