OSTEP Chapter 5 回顾
这里回顾第5章,本章介绍了插叙:进程API。
书籍介绍:
学习资料:
- https://pages.cs.wisc.edu/~remzi/OSTEP/
- https://github.com/remzi-arpacidusseau/ostep-translations/tree/master/chinese
- https://github.com/joshuap233/Operating-Systems-Three-Easy-Pieces-NOTES
参考资料:
- https://www.cnblogs.com/bwbfight/p/11181631.html
- https://blog.csdn.net/u014530704/article/details/73848573
- https://www.cnblogs.com/kunhu/p/3608109.html
- https://blog.csdn.net/qq_42914528/article/details/82023408
第5章 插叙:进程API
内容回顾
关键概念
- fork系统调用
- wait系统调用
- exec系统调用
作业(编码)
1
不改变$x$时值不变:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int x = 100;
printf("origin x value is %d\n", x);
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
// x = 50;
printf("x value in child process is %d, pid is %d\n", x, getpid());
} else {
// 父进程
// x = 20;
printf("x value in parent process is %d, pid is %d\n", x, getpid());
}
return 0;
}
运行:
╰─○ make p1 && ./p1
make: 'p1' is up to date.
origin x value is 100
x value in parent process is 100, pid is 471
x value in child process is 100, pid is 472
改变$x$时,子进程和父进程的值不同:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int x = 100;
printf("origin x value is %d\n", x);
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
x = 50;
printf("x value in child process is %d, pid is %d\n", x, getpid());
} else {
// 父进程
x = 20;
printf("x value in parent process is %d, pid is %d\n", x, getpid());
}
return 0;
}
运行:
╰─○ make p1 && ./p1
gcc -o p1 p1.c -Wall
origin x value is 100
x value in parent process is 20, pid is 528
x value in child process is 50, pid is 529
2
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
int fd = open("p2.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
if (fd < 0) {
fprintf(stderr, "open fail");
exit(1);
}
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
printf("fd in child process is %d, pid is %d\n", fd, getpid());
for (int i = 0; i < 1000; i++) {
write(fd, "child\n", 6);
}
} else {
// 父进程
printf("fd in parent process is %d, pid is %d\n", fd, getpid());
for (int i = 0; i < 1000; i++) {
write(fd, "parent\n", 7);
}
}
}
父子进程都可以访问fd,父进程和子进程会交替写入,即不会等待对方写入完成才进行自己的写入:
╰─○ make p2 && ./p2
gcc -o p2 p2.c -Wall
fd in parent process is 3, pid is 705
fd in child process is 3, pid is 706
p2.output:
parent
child
parent
child
parent
......
3
参考资料:
需要通过内存映射在不使用wait的条件达到目标:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
int main() {
int fd = open("p3.output", O_RDWR|O_CREAT|O_TRUNC, S_IRWXU);
if (fd < 0) {
fprintf(stderr, "open fail");
exit(1);
}
// 使其可以自动删除
unlink("p3.output");
// 改变文件大小
ftruncate(fd, 10);
// 映射
int *p = (int *)mmap(NULL, 10, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
fprintf(stderr, "mmap error");
exit(1);
}
*p = 1;
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
printf("hello\n");
*p = -1;
} else {
// 父进程等待p改变
while ((*p) > 0) {
}
printf("goodbye\n");
}
return 0;
}
运行:
╰─○ make p3 && ./p3
gcc -o p3 p3.c -Wall
hello
goodbye
4
参考资料:
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
printf("child pid is %d\n", getpid());
char *myargs[2];
myargs[0] = strdup("/bin/ls");
myargs[1] = NULL;
// execv(myargs[0], myargs);
// execvp(myargs[0], myargs);
// execl(myargs[0], myargs[0], NULL);
// execle(myargs[0], myargs[0], NULL, NULL);
execlp(myargs[0], myargs[0], NULL);
} else {
// 父进程
printf("parent pid is %d\n", getpid());
}
return 0;
}
运行:
╰─○ make p4 && ./p4
gcc -o p4 p4.c -Wall
parent pid is 956
child pid is 957
Makefile p1 p1.c p2 p2.c p2.output p3 p3.c p4 p4.c p5 p5.c p6 p6.c p7 p7.c p7.output p8 p8.c
之所以有这么多变种,推测是为了完成不同情形下的需求。
5
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
printf("child process's pid is %d\n", getpid());
int wc = wait(NULL);
printf("(child process): return value of wait is %d\n", wc);
} else {
// 父进程
int wc = wait(NULL);
printf("parent process's pid is %d\n", getpid());
printf("(parent process): return value of wait is %d\n", wc);
}
}
运行:
╰─○ make p5 && ./p5
gcc -o p5 p5.c -Wall
child process's pid is 1176
(child process): return value of wait is -1
parent process's pid is 1175
(parent process): return value of wait is 1176
子进程返回-1,因为子进程没有子进程;父进程返回子进程pid。
6
需要传入pid参数:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
printf("child process's pid is %d\n", getpid());
int wc = waitpid(rc, NULL, WUNTRACED);
printf("(child process): return value of wait is %d\n", wc);
} else {
// 父进程
// 等待直到rc终止
int wc = waitpid(rc, NULL, WUNTRACED);
printf("parent process's pid is %d\n", getpid());
printf("(parent process): return value of wait is %d\n", wc);
}
}
运行:
╰─○ make p6 && ./p6
gcc -o p6 p6.c -Wall
child process's pid is 1297
(child process): return value of wait is -1
parent process's pid is 1296
(parent process): return value of wait is 1297
7
没有输出,因为关闭了STDOUT_FILENO,但打开文件会得到结果。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
int main() {
close(STDOUT_FILENO);
printf("hello, world\n");
int fd = open("p7.output", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
if (fd < 0) {
fprintf(stderr, "open fail");
exit(1);
}
printf("hello, world\n");
return 0;
}
运行:
╰─○ ./p7
查看p7.out:
hello, world
hello, world
8
参考资料:
- https://www.cnblogs.com/kunhu/p/3608109.html
- https://blog.csdn.net/qq_42914528/article/details/82023408
思路:
关闭子进程的写端,只读;关闭父进程的读端,只写。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
int main() {
// I/O
int fd[2];
// message
char *message = "test message\n";
// 缓冲区
char buf[1024];
int result = pipe(fd);
if (result < 0) {
printf("pipe failed\n");
exit(1);
}
int rc = fork();
if (rc < 0) {
fprintf(stderr, "fork failed\n");
exit(1);
} else if (rc == 0) {
// 子进程
// 关闭写端
close(fd[1]);
printf("child process pid is %d\n", getpid());
// 读取父进程内容
int len = read(fd[0], buf, sizeof(buf));
if (len == 0) {
printf("don't get message from parent\n");
} else {
// 输出结果
write(STDOUT_FILENO, buf, len);
}
// 关闭读端
close(fd[0]);
} else {
// 父进程
// 关闭读端
close(fd[0]);
printf("parent process pid is %d\n", getpid());
write(fd[1], message, strlen(message));
// 关闭写端
close(fd[1]);
}
return 0;
}
运行:
╰─○ make p8 && ./p8
gcc -o p8 p8.c -Wall
parent process pid is 1592
child process pid is 1593
test message
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere