线程分叉时会发生什么?

我知道从一个线程调用fork() sys_call是一个坏主意。 但是,如果一个线程使用fork()创build一个新的进程会发生什么?

新进程将是创build线程的主线程的subprocess。 我认为。

如果其父节点首先完成,则新进程将被附加到init进程。 而它的父母是主线程,而不是创build它的线程。

纠正我,如果我错了。

 #include <stdio.h> #include <pthread.h> int main () { thread_t pid; pthread_create(&(pid), NULL, &(f),NULL); pthread_join(tid, NULL); return 0; } void* f() { int i; i = fork(); if (i < 0) { // handle error } else if (i == 0) // son process { // Do something; } else { // Do something; } } 

新进程将是创建线程的主线程的子进程。 我认为。

fork创造一个新的过程。 进程的父进程是另一个进程,而不是线程。 所以新流程的父母是旧流程。

请注意,子进程将只有一个线程,因为fork只会复制调用fork的(栈)线程。 (这不完全是真的:整个内存是重复的,但子进程只有一个活动线程。)

如果其父节点首先完成,则新进程将被附加到init进程。

如果父母首先完成SIGHUP信号发送给孩子。 如果孩子因为SIGHUP而不能退出,它将获得init作为其新父母。 另请参阅nohup的手册页和signal(7)了解SIGHUP更多信息。

而它的父母是主线程,而不是创建它的线程。

进程的父进程是一个进程,而不是一个特定的线程,所以说主线程或者子线程是父进程是没有意义的。 整个过程是父母。

最后一点:混合线和叉必须小心。 这里讨论一些陷阱。

但是,如果一个线程使用fork()创建一个新的进程会发生什么?

通过复制调用线程的地址空间(而不是整个进程的地址空间)将创建一个新的进程 。 这通常被认为是一个坏主意,因为很难做到这一点。 POSIX表示,子进程(在多线程程序中创建)只能调用异步信号安全函数,直到它调用其中一个exec*函数。

如果其父节点首先完成,则新进程将被附加到init进程。

子进程通常由init进程继承。 如果父进程是一个控制进程 (例如shell),那么POSIX需要 :

如果该过程是一个控制过程,则SIGHUP信号应发送到属于该调用过程的控制终端的前台进程组中的每个进程。

但是,对于大多数流程来说这不是事实,因为大多数流程并不是控制流程。

而它的父母是主线程,而不是创建它的线程。

分叉子的父母将始终是调用fork()的过程。 所以,PPID是子进程将是你的程序的PID。

问题源于fork(2)本身的行为。 每当使用fork(2)创建新的子进程时,新进程将获得新的内存地址空间,但是内存中的所有内容都是从旧进程中复制的(使用写时复制并非100%正确,但语义相同)。

如果我们在多线程环境中调用fork(2),那么执行调用的线程现在是新进程中的主线程,而在父进程中运行的所有其他线程都是死的。 而他们所做的一切就像在拨叉(2)之前一样。

现在想象一下,这些其他的线程在fork(2)调用之前愉快地做着他们的工作,几毫秒后他们就死定了。 如果这些现在已经死了的线程所做的事情不是完全保持原样呢?

让我举一个例子。 假设我们的主线程(即将调用fork(2)的线程)正在睡觉,而我们还有许多其他线程正在愉快地做一些工作。 分配内存,写入内容,复制内容,写入文件,写入数据库等等。 他们可能用malloc(3)来分配内存。 那么,事实证明,malloc(3)在内部使用一个互斥来保证线程安全。 正是这个问题。

如果其中一个线程正在使用malloc(3),并且在主线程fork(2)的同一时刻获得了互斥锁的锁定? 在新的子进程中,锁仍然保持 – 由一个现在已死的线程,谁永远不会返回它。

新的子进程将不知道是否安全使用malloc(3)。 在最坏的情况下,它将调用malloc(3)并阻塞,直到它获得锁,这将永远不会发生,因为应该返回它的线程已经死了。 这只是malloc(3)。 考虑所有其他可能的互斥锁和数据库驱动程序,文件处理库,网络库等。

为充分解释你可以通过这个链接 。