unix - 如何检查父子进程的状态?
问题描述
我刚刚编写了一段简单的代码来检查子进程和父进程的运行方式。但我没有得到想要的输出。
#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;
}
代码很简单,但是否有任何隐藏的问题会产生意外的输出?
解决方案
警告:答案不是律师规则!
是的。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
这里有一个内核级别的putch
操作stdout
,因为我认为一致性对于重新输入 23 行假代码并不重要。请注意,SYSCALL
s 由内核处理,因此是原子的(至少在处理文件描述符的输出时)。
这些指令中的每一个都是原子的。但是, 之后的所有内容都会SYSCALL fork_into_register_zero
以不同的 , 值运行两次REGISTER #0
,并且可以以任何方式交错。让它沉入其中。最后可能n
不会是8。事实上,输出可能是这样的:
Child process 3
Done Parent process exist 33
Done 3
好像不太对?那是给你穿线!
推荐阅读
- postgresql - 如何在 PostgreSQL 中一次创建数千或数百万个表?
- c - 在 Linux 中递归计算目录的最快的 C 代码(无文件)
- html - 单选按钮不会检查纯 HTML
- c# - C# 实体框架多个结果
- sql - 当 Oracle ACID 不完全遵守“隔离”属性时,它如何兼容?
- c++ - 堆栈后修复解析
- mule - Mulesoft 4,如何仅从 xml 文件中获取标签的值
- r - 将因子转换为日期时间,
2018 年 10 月 25 日(M、D、Y) - c++ - 如何让 GCC/Clang 警告未初始化成员的使用?
- shell - 如何修复已取消编辑,shell 中未进行任何更改