儿童和父母的执行流程

时间:2017-10-26 18:48:40

标签: c memory-management binary gdb posix

在网上看到我无法确定哪个进程在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中所做的观察不一致,有人可以填补我理解中的空白吗?

Fork Analysis Full

2 个答案:

答案 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给出:

  • 序列以A
  • 开头
  • 总共有两个As和四个B
  • 每个A后有两个B

AABBBB
ABABBB
ABBABB

是抢先式多任务操作系统上的所有可能输出。

P.S。如果没有Employed所说的话,这个答案是不完整的。