在网上看到我无法真正确定哪个进程在 child 或 parent
之前运行后,我计划在我的 PC 上禁用 ASLR 并运行调试器以查看我是否可以生成模式关于执行,我所做的观察在下面是 GitGist 到 GDB disas(完整)以及源代码
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
fork();
//fork();
printf("LINUX\n");
//printf("my pid is %d",(int) getpid());
fork();
printf("REDHAT\n");
//printf("my pid is %d",(int) getpid());
//fork();
return 0;
}
这是我在 gdb 中取消它时所说的代码,它给了我:-
gdb-peda$ disas main
Dump of assembler code for function main:
0x000000000000068a <+0>: push rbp
0x000000000000068b <+1>: mov rbp,rsp
0x000000000000068e <+4>: call 0x560 <fork@plt>
0x0000000000000693 <+9>: lea rdi,[rip+0xaa] # 0x744
0x000000000000069a <+16>: call 0x550 <puts@plt>
0x000000000000069f <+21>: call 0x560 <fork@plt>
0x00000000000006a4 <+26>: lea rdi,[rip+0x9f] # 0x74a
0x00000000000006ab <+33>: call 0x550 <puts@plt>
0x00000000000006b0 <+38>: mov eax,0x0
0x00000000000006b5 <+43>: pop rbp
0x00000000000006b6 <+44>: ret
End of assembler dump.
所以基本上它给了我一个执行的固定模式,所以我认为这应该意味着程序应该总是以特定的顺序执行我尝试了 disas main 大约 3 次以查看顺序是否真的改变了但它没有当我最终运行生成的二进制文件时,它给了我不同的输出
root@localhost:~/os/fork analysis# ./forkagain
LINUX
REDHAT
LINUX
REDHAT
REDHAT
REDHAT
root@localhost:~/os/fork analysis# ./forkagain
LINUX
LINUX
REDHAT
REDHAT
REDHAT
REDHAT
这与我在disas中所做的观察不一致,请有人填补我理解中的空白吗?
最佳答案
i tried disas main about 3 times to see if the order actually ever changes
顺序在编译时是固定的,因此如果不重新编译程序,它永远不会改变。
此外,顺序由您的程序源固定——不允许编译器对您的输出重新排序。
然后您观察到的是操作系统由于调用 fork
而引入的不确定性——在 fork
之后,无法保证哪个进程将首先运行,或者多长时间。 parent 可能会跑完,然后是 child 。或者 child 可能先跑完。或者它们都可以按时间片运行,比如一次一行。
此外,当今大多数非古老的 Linux 系统都运行在多处理器机器上,两个独立的进程在 fork 后可以同时运行。
另一个复杂的问题是你的程序没有明确定义,因为 stdio 缓冲。当您看到 6 行输出时,您可能很难解释这个结果:
./forkagain | wc -l
8
./forkagain > junk.out; cat junk.out
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
您应该在 fork
之前添加 fflush(stdout);
以避免这种复杂情况。
附言您还应该改掉以 root 身份运行的坏习惯——迟早您会犯下愚蠢的错误(例如在错误的目录中键入 rm -rf *
),您会非常抱歉您以 root 身份执行此操作。
关于c - Child 和 Parent 的执行流程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46961726/