如何检查父子进程的状态?

时间:2018-08-21 04:47:18

标签: unix process operating-system fork system-calls

我刚刚编写了一段简单的代码来检查子进程和父进程的运行方式。但是我没有得到想要的输出。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
    pid_t x;
    int n=1;
    x=fork();
    if(x>0)
    {
        n+=2;
        printf("Parent process exist %d\n",n);
    }
    else if(x==0)
    {
        n+=5;
        printf(" Child process %d\n ",n);
    }
    printf("done %d",n);
    return 0;
}

代码非常琐碎,但是有没有隐藏的问题会带来意想不到的输出?

1 个答案:

答案 0 :(得分:0)

警告:答案不符合法律规定!


是的。 n+=5不是原子操作。它由三个“子操作”组成:加载n,添加5,存储n

除非它甚至没有必要这样做,否则因为编译器可以自由运行“嘿;当我只将值保存在寄存器中时,所有将n加载和存储到RAM都是没有意义的”。声明变量volatile int来解决此问题。

通过以下示例代码的编译和执行(具有可变性),可以看出非原子性事物的重要性:

  0 SYSCALL fork_into_register_zero
  1 STORE 1 INTO RAM #386
  2 COMPARE REGISTER #0 TO 0
  3 JUMP IF <= TO INSTRUCTION #23
  4 LOAD RAM #386 INTO REGISTER #1
  5 ADD 2 TO REGISTER #1
  6 STORE REGISTER #1 INTO RAM #386
  7 LOAD "Parent process exist " INTO REGISTER #0
  8 LOAD 1 INTO REGISTER #1
  9 SYSCALL output_string_from_register_zero_to_file_descriptor_from_register_one
 10 LOAD 1000000 INTO REGISTER #2
 11 LOAD RAM #386 INTO REGISTER #1
 12 STORE REGISTER #1 INTO REGISTER #0
 13 DIVBY REGISTER #2 TO REGISTER #0
 14 ADD '0' TO REGISTER #0
 15 SYSCALL putch_from_register_zero
 16 MODBY REGISTER #2 TO REGISTER #1
 17 DIVBY 10 TO REGISTER #2
 18 COMPARE REGISTER #2 TO 0
 19 JUMP IF > TO INSTRUCTION #12
 20 STORE '\n' TO REGISTER #0
 21 SYSCALL putch_from_register_zero
 22 COMPARE 1 TO 0
 23 JUMP IF != TO INSTRUCTION 44
 24 LOAD RAM #386 INTO REGISTER #1
 25 ADD 5 TO REGISTER #1
 26 STORE REGISTER #1 INTO RAM #386
 27 LOAD " Child process " INTO REGISTER #0
 28 LOAD 1 INTO REGISTER #1
 29 SYSCALL output_string_from_register_zero_to_file_descriptor_from_register_one
 30 LOAD 1000000 INTO REGISTER #2
 31 LOAD RAM #386 INTO REGISTER #1
 32 STORE REGISTER #1 INTO REGISTER #0
 33 DIVBY REGISTER #2 TO REGISTER #0
 34 ADD '0' TO REGISTER #0
 35 SYSCALL putch_from_register_zero
 36 MODBY REGISTER #2 TO REGISTER #1
 37 DIVBY 10 TO REGISTER #2
 38 COMPARE REGISTER #2 TO 0
 39 JUMP IF > TO INSTRUCTION #12
 40 STORE '\n' TO REGISTER #0
 41 SYSCALL putch_from_register_zero
 42 STORE ' ' TO REGISTER #0
 43 SYSCALL putch_from_register_zero
 44 LOAD "Done " INTO REGISTER #0
 45 LOAD 1 INTO REGISTER #1
 46 SYSCALL output_string_from_register_zero_to_file_descriptor_from_register_one
 47 LOAD 1000000 INTO REGISTER #2
 48 LOAD RAM #386 INTO REGISTER #1
 49 STORE REGISTER #1 INTO REGISTER #0
 50 DIVBY REGISTER #2 TO REGISTER #0
 51 ADD '0' TO REGISTER #0
 52 SYSCALL putch_from_register_zero
 53 MODBY REGISTER #2 TO REGISTER #1
 54 DIVBY 10 TO REGISTER #2
 55 COMPARE REGISTER #2 TO 0
 56 JUMP IF > TO INSTRUCTION #12
 57 STORE '\n' TO REGISTER #0
 58 SYSCALL putch_from_register_zero
 59 STORE 0 TO REGISTER #0
 60 RETURN

这里有一个内核级别的putchstdout操作,因为我认为一致性不足以重新键入23行伪代码。请注意,SYSCALL由内核处理,也是由原子处理的(至少在处理输出到文件描述符时)。

这些指令中的每一个都是原子的。但是,SYSCALL fork_into_register_zero之后的所有内容都会使用不同的REGISTER #0值运行两次,并且可以以任何方式进行交错。让它沉入。最后,n可能不会是8。实际上,输出可能是这样的:

 Child process 3
 Done Parent process exist 33

Done 3

看起来不对吗?这就是您的线程!