C语言 使用'fork()`时,进程是否一直运行到终止

y0u0uwnf  于 2022-12-03  发布在  其他
关注(0)|答案(4)|浏览(197)

刚才有一个关于使用fork()的问题。假设我们决定fork() 3次,因此总共有8个进程。

int main() {
 fork();
 fork();
 fork();
 printf("First print statement.\n");
 printf("Second print statement.\n");
 return 0;
}

在本例中,我知道我们有8个不同的进程,即A, B, C, D, E, F, G, H。现在,我知道它们可以按任何顺序运行,因此A可能会先运行,但E可能会先运行,然后B,依此类推。我的问题是,如果不使用wait(NULL),而只使用这样的代码,一个进程是否必须在另一个进程运行之前完成运行?因此,输出是否必须

// Process A
First print statement.
Second print statement.

// Process E
First print statement.
Second print statement.

// Process B
First print statement.
Second print statement.

// etc...

或者我们可以有这样的东西:

// Process A
First print statement.
Second print statement.

// Process B
First print statement.

// Process E
First print statement.

// Process D
First print statement.

// Process B
Second print statement.

// Process D
Second print statement.

// etc...
b5buobof

b5buobof1#

这些进程同时运行。
wait()将等待下一个进程或waitpid()等待特定进程。它是一个同步原语,允许父进程获取正在终止的子进程的状态。

mrphzbgm

mrphzbgm2#

不,它不一定要在另一个程序占用CPU之前完成运行。这取决于CPU调度。

xkrw2x1b

xkrw2x1b3#

现在,我知道它们可以按任何顺序运行,所以A可以先运行,然后E可以运行,然后B,依此类推。
确切地说,用 * 进程 * 以任何顺序运行的说法并没有错,但这似乎给了你一个不正确的印象。在一个进程成功fork()之后,父进程和子进程 * 都 * 在同时运行。可以变化的是每个进程中的指令何时被调度在CPU上执行,因此,当任何一个进程的任何特定行为相对于另一个进程的行为表现出来时。就像任何其他并发运行的进程一样。
我的问题是,在不使用wait(NULL)的情况下,只使用这样的代码,一个进程是否必须在另一个进程运行之前完成运行?
不可以。粗略地说,所有活动进程都有资格获得CPU时间,并且系统会尽可能地将可用的CPU时间分配给所有进程。如果您有多个可用的处理单元(这在当今是很常见的),则组中的两个或更多进程可能会几乎同时执行指令。无论您有多少个处理单元,任何给定的进程在被抢占以允许其他进程运行之前通常都被限制在一定量的CPU时间内。wait() ing与这些都没有什么关系。
输出可能与第二个示例类似。

wlzqhblo

wlzqhblo4#

输出可以是任何顺序,唯一的限制是,对于每个进程,第一个语句(第一个printf())应该在第二个之前执行。实际的输出通常会显示一些进程有某种偏好,但这是内核安排调度它们的方式的结果,以及内核的实际数量,和上下文切换。如果您将stdout重定向到一个文件或将其通过管道传输到另一个进程,stdout变为总缓冲,每个进程完成输出将同时发生(由于write(2)系统调用没有完成,但是直到进程在返回main()之后调用exit(2),然后在一个系统调用中输出整个缓冲区。但这与stdout如何刷新它的缓冲区有关(在tty输出设备上,它在每个\n字符处刷新输出,而在文件或管道上,它只在缓冲区完全满的时候才刷新---这在你打印的数据量中是不会发生的),而不取决于内核的调度行为。
在您的示例中,八个进程仅在第一个write(2)处阻塞(好吧,8个不是,只有7个,另一个获得了锁,并且正在执行write系统调用),就像在执行write时一样(在系统中),输出设备inode在内核中被锁定,任何人都无法在锁定的inode上进入write(2),因此很有可能,当进程从write(2)返回时,它开始它的第二个write(2)(在第二次调用printf(3)时,如果在两次系统调用之间没有其他进程有机会获得锁,则再次获得锁)。但是没有理由使顺序不同,或者在loadad系统中,内核决定允许其他不同的进程在之前运行的进程之前运行。认为一个进程不是被抢占的,而是只有当从内核模式返回时,并且只有当其他进程获得了更高的优先级时(缓慢发生的事情)并且可以自由运行(对于为获取输出设备的inode而阻塞的其他进程,可能不会发生这种情况,这需要对它们进行调度)
可以观察到散布输出的唯一情况是,当具有锁的进程将要返回到用户模式时,内核调度已从inode锁唤醒的其他进程之一,并获取锁,但是如果这个进程没有被抢占(在多处理器系统中)处理器很难在已经运行索引节点锁之前获取该索引节点锁(实现这一点的时间很短,但这是可能的)
这是我得到的输出(在FreeBSD上,使用CoreDuo处理器---两个内核,我修改了你的例子,显示了printf()调用的作者的pid,以表明打印的进程有很大的可能性):

$ pru
[33781]: First print statement.
[33782]: First print statement.
[33787]: First print statement.
[33787]: Second print statement.
[33784]: First print statement.
[33784]: Second print statement.
[33788]: First print statement.
[33788]: Second print statement.
[33785]: First print statement.
[33785]: Second print statement.
[33786]: First print statement.
[33786]: Second print statement.
[33783]: First print statement.
[33783]: Second print statement.
[33782]: Second print statement.
[33781]: Second print statement.
$ _

相关问题