fork() 作为循环条件语句
fork() as loop condition statement
我有以下代码,我想解释这段代码中 fork() 调用的行为,中断条件作为命令行参数给出。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i = 0;
char *ptr;
int x = strtol(argv[1], &ptr, 10);
while (fork())
{
if (i == x)
{
break;
}
printf("PID: %d, PPID: %d, i = %d\n", getpid(), getppid(), i++);
}
return 0;
}
这是当命令行参数为 1 时的输出
PID: 684067, PPID: 14913, i = 0
PID: 684067, PPID: 14913, i = 0
我认为应该发生的是 fork()
调用将执行一次,创建一个子进程和父进程,向父进程返回一个非零进程 ID,向子进程返回一个零。
零值应被解释为 false,只有父进程会继续打印一次,然后将 i 的值递增到 1,然后再次重复创建另一个子进程,该子进程将再次不进入循环并作为 i = 1
这次它会跳出循环,那为什么我看到 2 条打印线而不是 1 条?
更高的 i 值的输出更令人费解,但可以预见地打印 i*(i+3)/2 lines。
谁能解释我假设中的缺陷?
您看到的重复消息来自 stdio 缓冲,事实上 printf
默认情况下实际上不打印 - 它只是将一些内容放入缓冲区,稍后将在缓冲区被打印时打印刷新(如果不是在显式刷新或缓冲区填满之前退出,则在进程退出时发生)。
最重要的是,当您派生 child 时,child 会获得所有 parent 状态的副本——包括所有 stdio 缓冲区。因此,如果 stdio 缓冲区中有任何 un-flushed 数据,该数据将被复制并(最终)写入两次——一次由 parent 一次由 child.
您可以通过在 printf
之后放置明确的 fflush(stdout);
来避免这种情况。
使问题复杂化的是,stdio 还支持一种叫做“行缓冲模式”的东西,在这种模式下,每次写入换行符时它都会自动刷新一个 FILE。在某些系统上,这是默认设置在 stdout 上,但在其他系统上不是(它是实现定义的)。您可以通过在 main 函数的开头使用 setlinebuf(stdout);
在 stdout 上显式设置 line-buffered 模式来利用这一点。
我有以下代码,我想解释这段代码中 fork() 调用的行为,中断条件作为命令行参数给出。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i = 0;
char *ptr;
int x = strtol(argv[1], &ptr, 10);
while (fork())
{
if (i == x)
{
break;
}
printf("PID: %d, PPID: %d, i = %d\n", getpid(), getppid(), i++);
}
return 0;
}
这是当命令行参数为 1 时的输出
PID: 684067, PPID: 14913, i = 0
PID: 684067, PPID: 14913, i = 0
我认为应该发生的是 fork()
调用将执行一次,创建一个子进程和父进程,向父进程返回一个非零进程 ID,向子进程返回一个零。
零值应被解释为 false,只有父进程会继续打印一次,然后将 i 的值递增到 1,然后再次重复创建另一个子进程,该子进程将再次不进入循环并作为 i = 1
这次它会跳出循环,那为什么我看到 2 条打印线而不是 1 条?
更高的 i 值的输出更令人费解,但可以预见地打印 i*(i+3)/2 lines。
谁能解释我假设中的缺陷?
您看到的重复消息来自 stdio 缓冲,事实上 printf
默认情况下实际上不打印 - 它只是将一些内容放入缓冲区,稍后将在缓冲区被打印时打印刷新(如果不是在显式刷新或缓冲区填满之前退出,则在进程退出时发生)。
最重要的是,当您派生 child 时,child 会获得所有 parent 状态的副本——包括所有 stdio 缓冲区。因此,如果 stdio 缓冲区中有任何 un-flushed 数据,该数据将被复制并(最终)写入两次——一次由 parent 一次由 child.
您可以通过在 printf
之后放置明确的 fflush(stdout);
来避免这种情况。
使问题复杂化的是,stdio 还支持一种叫做“行缓冲模式”的东西,在这种模式下,每次写入换行符时它都会自动刷新一个 FILE。在某些系统上,这是默认设置在 stdout 上,但在其他系统上不是(它是实现定义的)。您可以通过在 main 函数的开头使用 setlinebuf(stdout);
在 stdout 上显式设置 line-buffered 模式来利用这一点。