dev*_*ium 8 unix multithreading fork process
我在理解如何使用Unix方面遇到了一些麻烦fork()
.我习惯于在需要并行化时,在我的应用程序中生成线程.它始终是形式的东西
CreateNewThread(MyFunctionToRun());
void myFunctionToRun() { ... }
Run Code Online (Sandbox Code Playgroud)
现在,在学习Unix时fork()
,我得到了表单的例子:
fork();
printf("%d\n", 123);
Run Code Online (Sandbox Code Playgroud)
其中fork之后的代码是"拆分"的.我无法理解fork()如何有用.为什么fork()与上面的CreateNewThread()没有类似的语法,你传递它想要运行的函数的地址?
为了完成类似于CreateNewThread()的事情,我必须要有创造力并做类似的事情
//pseudo code
id = fork();
if (id == 0) { //im the child
FunctionToRun();
} else { //im the parent
wait();
}
Run Code Online (Sandbox Code Playgroud)
也许问题是我习惯于以.NET方式生成线程,我无法清楚地思考这个问题.我在这里错过了什么?有什么优势fork()
了CreateNewThread()
?
PS:我知道fork()
会产生一个新进程,同时CreateNewThread()
会产生一个新线程.
谢谢
fork()
他说:"将当前流程状态复制到一个新流程中,并从此处开始运行." 因为代码然后在两个进程中运行,它实际上返回两次:一次在父进程中(在那里它返回子进程的进程标识符),一次在子进程中(在它返回零的情况下).
在子进程之后调用的安全性有很多限制fork()
(见下文).期望是fork()
调用是产生运行具有其自身状态的新可执行文件的新进程的第一部分.此过程的第二部分是execve()
对其变体的调用,或者其中一个变体,它指定要加载到当前正在运行的进程中的可执行文件的路径,要提供给该进程的参数以及围绕该进程的环境变量.(没有什么可以阻止你重新执行当前正在运行的可执行文件,并提供一个标志,使其在父节点停止的地方进行提取,如果这是你真正想要的那样.)
UNIX fork()-exec()
舞蹈大致相当于Windows CreateProcess()
.更新的功能更像是:posix_spawn()
.
作为使用的实际例子fork()
,考虑一个shell,例如bash
.fork()
由命令shell一直使用.当你告诉shell运行程序(例如echo "hello world"
)时,它会自行分配然后执行该程序.管道是与分叉进程的集合stdout
和stdin
由之间的父适当装配了fork()
和exec()
.
如果要创建新线程,则应使用Posix线程库.您使用创建一个新的Posix线程(pthread)pthread_create()
.您的CreateNewThread()
示例如下所示:
#include <pthread.h>
/* Pthread functions are expected to accept and return void *. */
void *MyFunctionToRun(void *dummy __unused);
pthread_t thread;
int error = pthread_create(&thread,
NULL/*use default thread attributes*/,
MyFunctionToRun,
(void *)NULL/*argument*/);
Run Code Online (Sandbox Code Playgroud)
在线程可用之前,fork()
UNIX是最接近多线程的东西.现在线程可用,使用fork()
几乎完全限于生成执行不同可执行文件的新进程.
下面:限制是因为fork()
早于多线程,所以只有调用的线程fork()
继续在子进程中执行.按POSIX:
应使用单个线程创建进程.如果多线程进程调用fork(),则新进程应包含调用线程的副本及其整个地址空间,可能包括互斥锁和其他资源的状态.因此,为了避免错误,子进程可能只执行异步信号安全操作,直到调用其中一个exec函数为止.[THR] [Option Start]可以通过pthread_atfork()函数建立fork处理程序,以便跨fork()调用维护应用程序不变量.[选项结束]
当应用程序从信号处理程序调用fork()并且由pthread_atfork()注册的任何fork处理程序调用不是异步信号安全的函数时,行为是未定义的.
因为您调用的任何库函数都可能代表您生成一个线程,所以偏执的假设是您始终只能在调用fork()
和调用之间的子进程中执行异步信号安全操作exec()
.
除了历史之外,在资源所有权和流程与线程之间的生命周期方面存在一些根本差异.
fork时,新进程占用一个完全独立的内存空间.这与创建新线程非常重要.在多线程应用程序中,您必须考虑如何访问和操作共享资源.已经分叉的已处理必须使用进程间方式显式共享资源,例如共享内存,管道,远程过程调用,信号量等.
另一个区别是fork()'ed的子节点可以比它们的父节点寿命更长,因为当进程终止时所有线程都会死掉.
在客户端 - 服务器架构中,预期非常非常长的正常运行时间,使用fork()而不是创建线程可能是一种有效的策略来对抗内存泄漏.您不必担心清除线程中的内存泄漏,而只是分叉一个新的子进程来处理每个客户端请求,然后在完成时杀死它.然后,唯一的内存泄漏源是调度事件的父进程.
类比:您可以将产生线程视为在单个浏览器窗口中打开选项卡,而分叉就像打开单独的浏览器窗口一样.
要问为什么CreateNewThread
不仅仅返回一个类似于fork()
... 的线程ID 会更有效.毕竟fork()
设置一个先例.你的意见只是在你看到一个在另一个之前.退后一步,考虑fork()
复制过程并继续执行......比下一条指令更好的地方?为什么通过在讨价还价中添加一个函数调用来复杂化(然后只需要一个void*
)?
你对Mike的评论说:"我无法理解你在哪种情况下想要使用它." .基本上,您可以在需要时使用它:
BTW /使用UNIX/Linux并不意味着你必须放弃fork()
进程的线程...... pthread_create()
如果你对线程范例更加熟悉,你可以使用和相关的函数.