可以确定fork()的执行顺序吗?
我正在练习教科书“操作系统概念第7版”,我对fork()
工作方式有点困惑。 根据我的理解, fork()
创建一个与其父进程并发运行的子进程。 但是,我们如何确切知道哪个进程首先运行? 我的意思是执行的顺序。
问题
使用fork()
系统调用编写C程序,该系统调用在子进程中生成Fibonacci序列。 序列号将在命令行中提供。
这是我的解决方案:
#include #include #include #include void display_fibonacci_sequence( int n ) { int i = 0; int a = 1; int b = 1; int value; printf( "%d, %d, ", a, b ); for( ;i < n - 2; ++i ) { value = a + b; printf( "%d, ", value ); a = b; b = value; } printf( "\n" ); } int main( int argc, char** argv ) { int n; pid_t pid; pid = fork(); if( argc != 2 ) { fprintf( stderr, "Invalid arguments" ); exit( -1 ); } n = atoi( argv[1] ); if( pid < 0 ) { fprintf( stderr, "Fork failed" ); exit( -1 ); } else if( pid == 0 ) { display_fibonacci_sequence( n ); } else { // parent process // what do we need to do here? } }
说实话,我认为使用fork
和不使用fork
之间没有任何区别。 此外,如果我希望父进程处理来自用户的输入,并让子进程处理显示,我该怎么办呢?
我们不知道哪个先运行,父母或孩子。 这就是为什么父进程通常必须等待子进程完成,如果它们之间存在对执行顺序的依赖。
在您的特定问题中,没有任何特殊原因使用fork()
。 你的教授可能只是为了一个简单的例子而给你这个。
如果您希望父级处理输入并计算要计算的子级,您只需将调用移动到处理命令行参数的点下方的fork()
。 使用与上面相同的基本逻辑,让孩子调用display_fibonacci_sequence
,让父母等待
你问了很多问题,我会尝试以方便的顺序回答它们。
第一个问题
说实话,我认为使用fork和不使用fork之间没有任何区别。
那是因为这个例子不是很好。 在您的示例中,父级不执行任何操作,因此fork无用。
第二
else { // what do we need to do here? }
您需要等待(2)让孩子终止。 请务必仔细阅读该页面。
第三
我希望父进程处理来自用户的输入,并让子进程处理显示
在fork之前读取输入并“处理”内部显示if (pid == 0)
第四
但是,我们如何确切知道哪个进程首先运行?
很少有节目应该关注这一点。 您无法知道执行的顺序,它完全取决于环境。 TLPI说:
在fork()之后,不确定哪个进程 – 父进程或子进程可以访问CPU。 在多处理器系统上,它们可以同时访问CPU。
为了获得正确的结果,隐式或明确依赖于特定执行顺序的应用程序可能会因竞争条件而失败
也就是说,操作系统可以让您控制此订单。 例如,Linux有/proc/sys/kernel/sched_child_runs_first
。
选择运行system scheduler
选择的进程,与操作系统上运行的任何其他应用程序不同。 生成的进程被视为调度程序在队列中分配优先级或点或任何实现的任何其他进程。
虽然您无法控制在fork
之后首先调度哪个进程(父进程或子进程)(事实上在SMP /多核上它可能都是 !),有很多方法可以同步这两个进程,让一个等待直到另一个到达某一点在它执行任何重要的操作之前。 一种经典的,非常便携的方法如下:
- 在
fork
之前,调用pipe
来创建管道。 - 在
fork
之后,想要等待的进程应该立即关闭管道的写入端并在管道的读取端调用read
。 - 另一个进程应立即关闭管道的读取端,并等待关闭管道的写入端,直到它准备好让另一个进程运行。 (
read
将在另一个过程中返回0)
但是,我们如何确切知道哪个进程首先运行? 我的意思是执行的顺序。
无法保证首先运行哪一个。 如果是子节点,则fork
返回0
如果是父节点,则返回子节点的pid
。 从理论上讲,它们可以在多处理器系统上完全同时运行。 如果您确实想要确定哪个先运行,那么您可以在两个进程之间拥有共享锁。 首先获得锁定的那个可以说先跑了。
关于在你的其他声明中做什么。 您将要等待子进程使用wait
或waitpid
退出。
说实话,我认为使用
fork
和不使用fork
之间没有任何区别。
不同之处在于您创建了子进程。 系统进行计算的另一个过程。 对于这个简单的问题,最终用户体验是相同的。 但是当你编写像需要同时处理事物的服务器这样的系统时, fork
就大不相同了。
此外,如果我希望父进程处理来自用户的输入,并让子进程处理显示,我该怎么办呢?
您似乎已经具有该设置。 父进程只需要等待子进程完成。 子进程将结果printf
到终端。 父进程当前从命令行获取用户输入。