fork()
函数的作用是“将当前进程状态复制到一个新进程,并从此处开始运行它”。由于代码现在在两个进程中运行,因此实际上会返回两次:一次在父进程中(其中它返回子进程的进程标识符),一次在子进程中(其中它返回零)。
在fork()
之后,在子进程中调用哪些函数是安全的有很多限制(请参见下文)。期望的是,fork()
调用是生成运行具有自己状态的新可执行文件的新进程的第一部分。这个过程的第二部分是调用execve()
或其变体之一,指定要加载到当前正在运行的进程中的可执行文件的路径、要提供给该进程的参数以及要包围该进程的环境变量。(如果您真的想这样做,没有任何阻止您重新执行当前正在运行的可执行文件并提供一个标志,使其从父进程离开的地方继续执行。)
UNIX中的fork()-exec()
操作大致相当于Windows的CreateProcess()
操作。更像它的是一个较新的函数:posix_spawn()
。
使用fork()
的一个实际例子是shell,例如bash
。命令shell一直在使用fork()
。当您告诉shell运行一个程序(例如echo "hello world"
)时,它会fork自己,然后exec该程序。管道是由父进程在fork()
和exec()
之间适当地设置stdout
和stdin
的分叉进程集合。
如果要创建新线程,应使用Posix线程库。使用pthread_create()
创建新的Posix线程(pthread)。您的CreateNewThread()
示例将如下所示:
#include <pthread.h>
void *MyFunctionToRun(void *dummy __unused);
pthread_t thread;
int error = pthread_create(&thread,
NULL,
MyFunctionToRun,
(void *)NULL);
在线程问世之前,
fork()
是UNIX提供的最接近多线程的东西。现在有了线程,使用
fork()
几乎完全限制于生成一个新进程以执行不同的可执行文件。
下面是由于
fork()
先于多线程而出现的限制,因此只有调用
fork()
的线程在子进程中继续执行。根据
POSIX:
将创建带有单个线程的进程。如果多线程进程调用fork(),则新进程将包含一个调用线程及其整个地址空间的副本,可能包括互斥锁和其他资源的状态。因此,为了避免错误,在执行任何exec函数之前,子进程只能执行异步信号安全操作。[THR] [Option Start] 可以通过pthread_atfork()函数建立fork处理程序,以维护应用程序不变式跨fork()调用[Option End]
当应用程序从信号处理程序调用fork()并且pthread_atfork()注册的任何fork处理程序调用了一个不是异步信号安全的函数时,行为未定义。
因为您调用的任何库函数都可能代表您生成线程,所以偏执的假设是,在调用
fork()
和
exec()
之间,您总是被限制执行异步信号安全操作。