我正在自学“操作系统概念”,并且正在研究 chp3。工艺部分。
有一个示例,其中调用“fork()”函数并取决于返回的 pid 值,如下所示:
pid=fork();
if(pid<0){ //error stuff
}
else if(pid==0){
// child process stuff
}
else{
// parent process stuff
}
这里让我困惑的是,如果执行这段代码,在“if”的三种情况中,只会执行一种,这意味着父/子过程中只会执行一种。
但仔细读了一下,我发现有一句话可以帮助我解决困惑,但不能完全解决。
新进程由原始进程的地址空间的副本组成。
根据我的想象,我猜这意味着每当执行“fork()”调用时,当原始 c 代码将作为“父”运行时,该代码的精确副本将被复制并作为“子”进程运行。 。
我这样理解对吗?
另外,“地址空间”与此有什么关系?再次,利用我的想象力,我假设,由于父代码的执行意味着代码被加载到 RAM 并在它将有一段 RAM 分配给代码的地方执行,因此该段将被复制到其他地方的新段位于 RAM 中并分配给子进程。
我的理解正确吗?
答案1
是的,你是对的。
特别是,这意味着子进程将从父进程继承所有变量以及它们在分叉时所拥有的值。但是,如果在稍后的步骤中父进程或子进程之一修改了这些变量之一,则该修改将是该进程的本地修改:如果子进程修改变量,父进程仍将看到旧值而不是新值。
对于分叉,如果您希望子进程和父进程进行通信,则需要使用一些显式的进程间通信。
这就是与线程的区别。从概念上讲,分叉和线程看起来相同:在分叉的情况下由两个进程执行相同的代码,在线程的情况下由两个线程执行相同的代码。然而,在线程的情况下,地址空间不会被复制:两个线程将共享相同的内存,因此如果一个线程修改一个变量,它将影响所有其他线程。
因此,线程允许线程之间非常灵活的通信,但这也很容易出错,因为如果不小心使用,很可能出现竞争条件。
这两个系统都满足不同的需求。附带说明一下,分叉原语通常在系统端以巧妙的方式实现,因为地址空间不会被物理复制,但系统将使用写时复制系统:仅当满足以下条件之一时才会复制数据:进程尝试实际修改它。虽然数据没有被修改,但它不会被复制,因此不会消耗更多内存。
有关叉子和螺纹的更多信息可以在 StackOverflow 上找到。