OSTEP:进程的简单使用
第五章:进程API
子进程和父进程的变量
x
的值内容相互独立。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int x = 100;
int rc = fork();
if (rc < 0)
{
printf("fork failed\n");
exit(1);
}
else if (rc == 0)
{
// child process
printf("Child: %d\n", x);
// 子进程变量增加100
x += 100;
printf("Child + 100: %d\n", x);
}
else
{
// 父进程在子进程执行完毕后执行
int wc = wait(NULL);
// parent process
printf("Parent: %d\n", x);
// 父进程变量增加100
x += 100;
printf("Parent + 100: %d\n", x);
}
// 分别再次输入最后的值
printf("Final Address: %d\n", x);
return 0;
}测试结果如下:
1
2
3
4
5
6Child: 100
Child + 100: 200
Final Address: 200
Parent: 100
Parent + 100: 200
Final Address: 200同时打开文件
p4.output
并且分别写入Child process
和Parent Process
,可以正常并发写入。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
int main()
{
// close stdout and open output file
close(STDOUT_FILENO);
open("./p4.output", O_CREAT | O_WRONLY | O_TRUNC, 0700);
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0)
{
printf("Child process\n");
}
else
{
printf("Parent process\n");
}
return 0;
}结果(p4.output文件)
1
2Child process
Parent process或(并发输出的先后顺序不同)
1
2Parent process
Child process题目要求的是在不适用
wait()
函数下实现子进程和父进程的先后,通过vfork()
函数可以实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
int main()
{
// close stdout and open output file
close(STDOUT_FILENO);
open("./p4.output", O_CREAT | O_WRONLY | O_TRUNC, 0700);
int rc = vfork();
if (rc < 0)
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0)
{
printf("Child process\n");
}
else
{
printf("Parent process\n");
}
return 0;
}数据结果可以参考题目2的第一个情况。不过这里插入Stack Overflow上书原作者的话作为备注:
Without calling wait() is hard, and not really the main point. What you did – learning about signals on your own – is a good sign, showing you will seek out deeper knowledge. Good for you!
Later, you’ll be able to use a shared memory segment, and either condition variables or semaphores, to solve this problem.
针对不同的调用和变种,写了一篇详细的博客进行解析:区分不同exec()形式
在父进程使用
wait()
,等待子进程完成后,wait()
会返回子进程的pid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20int main()
{
int rc = fork();
if (rc < 0)
{
cout << "fork failed" << endl;
exit(1);
}
else if (rc == 0)
{
printf("I am child process %d\n", getpid());
}
else
{
int ws = wait(NULL);
printf("I am parent process %d\n", getpid());
printf("Return Value of wait() is %d\n", ws);
}
return 0;
}运行结果
1
2
3I am child process 4878
I am parent process 4873
Return Value of wait() is 4878在子进程中使用wait()则会返回
-1
,并且在失败后依旧会执行当前子进程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23int main()
{
int rc = fork();
if (rc < 0)
{
cout << "fork failed" << endl;
exit(1);
}
else if (rc == 0)
{
int fake_ws = wait(NULL);
printf("I am child process %d\n", getpid());
printf("fake_ws = %d\n", fake_ws);
printf("Test\n");
}
else
{
int ws = wait(NULL);
printf("I am parent process %d\n", getpid());
printf("Return Value of wait() is %d\n", ws);
}
return 0;
}运行结果
1
2
3
4
5I am child process 5011
fake_ws = -1
Test
I am parent process 5006
Return Value of wait() is 5011针对
waitpid()
的使用,总结了笔记:waitpid()调用子进程中关闭标准输出,父进程输出子进程和本身
pid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20int main()
{
int rc = fork();
if (rc < 0)
{
printf("fork failed\n");
exit(1);
}
else if (rc == 0)
{
close(STDOUT_FILENO);
printf("Hello from child\n");
}
else
{
int ws = wait(NULL);
printf("Hello from parent, child exited with status %d\n", ws);
}
return 0;
}运行结果,子进程中的输出被关闭,只有父进程输出。
1
Hello from parent, child exited with status 1326
通过pipe()管道进行传输数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43int main()
{
int fd[2]; // 创建两个文件标示符
int rc_pipe = pipe(fd); // 创建管道
char msg[] = "Hello_World!"; // 用于输出的字符串
char buff[100]; // 用于输出的缓冲区
int rc_1 = fork(); // 创建第一个进程
if (rc_1 == 0)
{
for (int i = 0; i < 5; i++)
{
printf("Child Process 1: %d\n", i);
sleep(1);
}
close(fd[0]); // 为防止文件读写出现问题,关闭读取端,只允许写入
dup2(fd[1], STDOUT_FILENO); // 将标准输出重定向到管道的写入端
printf("%s", msg); // 输出字符串到标准输出,然后重定向至管道的写入端
close(fd[1]); // 关闭管道的写入端
exit(0); // 结束当前进程
}
int rc_2 = fork();
if (rc_2 == 0)
{
// 即使通过sleep()让第二个进程等待,由于第一个进程的输入管道没有内容,所以第二个进程的scanf会等待至第一个进程将数据写入缓冲区
for (int i = 0; i < 3; i++)
{
printf("Child Process 2: %d\n", i);
sleep(1);
}
close(fd[1]); // 为防止文件读写出现问题,关闭写入端,只允许读取
dup2(fd[0], STDIN_FILENO); // 将标准输入重定向到管道的读取端
scanf("%s", buff); // 从标准输入读取字符串,然后重定向至管道的读取端
close(fd[0]); // 关闭管道的读取端
printf("%s", buff); // 输出由管道传输的字符串
exit(0); // 结束当前进程
}
return 0;
}输出结果
1
2
3
4
5
6
7
8
9Child Process 1: 0
Child Process 2: 0
Child Process 2: 1
Child Process 1: 1
Child Process 2: 2
Child Process 1: 2
Child Process 1: 3 # 从这个时候开始,rc_2在等待rc_1通过管道传入"Hello World!"
Child Process 1: 4
Hello_World! # rc_2通过管道读取到了内容,进行输出
OSTEP:进程的简单使用
https://halc.top/p/897b63ef