在网上看到我无法确定哪个进程在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中对它进行disas时它给了我: -
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主要约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中所做的观察不一致,有人可以填补我理解中的空白吗?
答案 0 :(得分:3)
我试过disas main大约3次,看看订单是否真的有变化
订单在编译时是固定的,因此如果不重新编译程序,永远不会更改。
此外,订单由您的程序源修复 - 不允许编译器重新排序您的输出。
你观察到的是操作系统因调用fork
而引入的不确定性 - 在fork
之后,无法保证哪个进程将首先运行,或者运行多长时间。父母可能会跑完,然后是孩子。或者孩子可能先跑完成。或者他们都可以用时间切片运行,一次说一行。
此外,目前大多数非古老的Linux系统都在多处理器机器上运行,两个独立的进程可以在fork之后同时运行 。
另一个复杂因素是由于stdio缓冲,你的程序没有明确定义。当你看到6行输出时,你可能很难解释这个结果:
./forkagain | wc -l
8
./forkagain > junk.out; cat junk.out
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
LINUX
REDHAT
您应该在fflush(stdout);
之前添加fork
以避免此并发症。
P.S。你也应该学习以root身份运行的坏习惯 - 迟早你会犯一个愚蠢的错误(比如在错误的目录中输入rm -rf *
),真的很抱歉你做到了根
答案 1 :(得分:2)
每个流程都以完美定义的顺序执行。这里的诀窍是,不能保证每个进程都会在一个tick中执行(进程占用执行单元的时间)并且无法保证从同一进程分叉的两个进程将在分叉的顺序。
如果我们假设A(LINUX)和B(REDHAT)的打印是基准,那么你可以得到任何序列的As和Bs给出:
AABBBB
ABABBB
ABBABB
是抢先式多任务操作系统上的所有可能输出。
P.S。如果没有Employed所说的话,这个答案是不完整的。