Child 和 Parent 的执行流程
Execution Flow of Child and Parent
在网上看到我无法真正确定 运行 之前是哪个进程,即 child or 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中的观察不一致,请有人填补我理解中的空白吗?
每个进程都按照完美定义的顺序执行。这里的技巧是不能保证每个进程都会在一个 tick(进程占用执行单元的时间段)内执行,也不能保证从同一个进程派生的两个进程会在分叉顺序。
如果我们假设 A (LINUX) 和 B (REDHAT) 的打印是基准,那么您可以获得 A 和 B 的任意序列,前提是:
- 序列以 A 开头
- 一共有两个A,四个B
- 每个A后面有两个B
AABBBB
ABABBB
阿巴巴
是抢占式多任务处理的所有可能输出 OS。
P.S。如果没有 Employed 的话,这个答案是不完整的。
i tried disas main about 3 times to see if the order actually ever changes
顺序在编译时固定,因此如果不重新编译程序,它永远不会改变。
此外,顺序由您的程序源决定——不允许编译器re-order您的输出。
然后您观察到的是 OS 由于调用 fork
而引入的不确定性——在 fork
之后,无法保证哪个进程将 运行 第一,或者多长时间。 parent可以运行完成,然后child。或者 child 可能 运行 先完成。或者他们可以 运行 和 time-slicing,一次说一行。
此外,当今大多数 non-ancient Linux 系统都 运行ning 在 multi-processor 机器上,两个独立的进程可以 运行 同时分叉后
另一个复杂的问题是您的程序不是 well-defined,因为 stdio 缓冲。当您看到 6 行输出时,您可能很难解释这个结果:
./forkagain | wc -l
8
./forkagain > junk.out; cat junk.out
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
您应该在 fork
之前添加 fflush(stdout);
以避免这种并发症。
P.S。你还应该 un-learn 以 root 身份 运行 的坏习惯——迟早你会犯一个愚蠢的错误(比如在错误的目录中键入 rm -rf *
),并且真的抱歉,您是以 root 身份执行的。
在网上看到我无法真正确定 运行 之前是哪个进程,即 child or 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中的观察不一致,请有人填补我理解中的空白吗?
每个进程都按照完美定义的顺序执行。这里的技巧是不能保证每个进程都会在一个 tick(进程占用执行单元的时间段)内执行,也不能保证从同一个进程派生的两个进程会在分叉顺序。
如果我们假设 A (LINUX) 和 B (REDHAT) 的打印是基准,那么您可以获得 A 和 B 的任意序列,前提是:
- 序列以 A 开头
- 一共有两个A,四个B
- 每个A后面有两个B
AABBBB
ABABBB
阿巴巴
是抢占式多任务处理的所有可能输出 OS。
P.S。如果没有 Employed 的话,这个答案是不完整的。
i tried disas main about 3 times to see if the order actually ever changes
顺序在编译时固定,因此如果不重新编译程序,它永远不会改变。
此外,顺序由您的程序源决定——不允许编译器re-order您的输出。
然后您观察到的是 OS 由于调用 fork
而引入的不确定性——在 fork
之后,无法保证哪个进程将 运行 第一,或者多长时间。 parent可以运行完成,然后child。或者 child 可能 运行 先完成。或者他们可以 运行 和 time-slicing,一次说一行。
此外,当今大多数 non-ancient Linux 系统都 运行ning 在 multi-processor 机器上,两个独立的进程可以 运行 同时分叉后
另一个复杂的问题是您的程序不是 well-defined,因为 stdio 缓冲。当您看到 6 行输出时,您可能很难解释这个结果:
./forkagain | wc -l
8
./forkagain > junk.out; cat junk.out
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
您应该在 fork
之前添加 fflush(stdout);
以避免这种并发症。
P.S。你还应该 un-learn 以 root 身份 运行 的坏习惯——迟早你会犯一个愚蠢的错误(比如在错误的目录中键入 rm -rf *
),并且真的抱歉,您是以 root 身份执行的。