线程分叉时会发生什么?

Ton*_*ous 5 c linux operating-system fork pthreads

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

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

如果其父级首先完成,则新进程将附加到init进程.它的父级是主线程,而不是创建它的线程.

如果我错了,请纠正我.

#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;
     }
 }
Run Code Online (Sandbox Code Playgroud)

Kla*_*äck 14

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

fork创造一个新的过程.进程的父进程是另一个进程,而不是线程.因此,新流程的父级是旧流程.

请注意,子进程只有一个线程,因为fork只复制调用的(堆栈)线程fork.(这不完全正确:整个内存重复,但子进程只有一个活动线程.)

如果其父级首先完成,则新进程将附加到init进程.

如果父母完成,则首先SIGHUP向孩子发送信号.如果孩子没有退出,SIGHUP那么它将init成为新的父母.另请参见手册页nohupsignal(7)对更多的信息SIGHUP.

它的父级是主线程,而不是创建它的线程.

进程的父进程是进程,而不是特定的线程,因此说主线程或子线程是父进程是没有意义的.整个过程是父母.

最后要注意的是:混合线和叉必须小心.这里讨论了一些陷阱.

  • 仅当父进程是每个 POSIX 的控制进程时,才会发送 SIGHUB。子进程很少收到 SIGHUB。 (2认同)

P.P*_*.P. 5

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

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

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

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

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

但是,这对于大多数流程而言并非如此,因为大多数流程都不是控制流程。

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

fork 子进程的父进程将始终是调用 fork() 的进程。因此,PPID 是子进程,将是您程序的 PID。


Mec*_*cki 5

如果我错了,请纠正我。

会做 :)

fork()POSIX 系统调用一样,它的行为是明确定义的:

一个进程应使用单个线程创建。如果多线程进程调用 fork(),新进程应包含调用线程及其整个地址空间的副本,可能包括互斥锁和其他资源的状态。因此,为了避免错误,子进程可能只执行异步信号安全操作,直到调用 exec 函数之一。

https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html

分叉的孩子是其父级的完全副本,但只有fork()在父级中调用的线程仍然存在于子级中,并且是该子级的新主线程,直到您调用exec().

POSIX 解密“应使用单个线程创建”具有误导性,因为实际上大多数实现将真正创建父进程的完全副本,因此所有其他线程及其内存也被复制,这意味着线程实际上在那里,它们只是不能再运行了,因为系统从不为它们分配任何 CPU 时间(它们在调度程序表中丢失)。

一个更简单的心理形象如下:

当父进程调用 fork 时,整个进程会被冻结片刻,原子复制,然后父进程整体解冻,而在子进程中,只有调用 fork 的一个线程被解冻,其他一切都保持冻结状态。

这就是为什么在两者之间执行某些系统调用fork()并没有保存的原因,exec()正如 POSIX 标准所指出的那样。理想情况下,除了关闭或复制文件描述符、设置或恢复信号处理程序然后调用exec().