ostep homework(5)

本文最后更新于:1 年前

第5章 插叙:进程API homework详解

实验环境

笔者采用的是Ubuntu22.04的虚拟机。
本次作业原则上只需自己编码,不需要依靠实验材料,不过作者也提供了两个py程序可供参考,文件名为cpu-api。

实验内容

1

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
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
int x = 100;
printf("%d (pid:%d)\n", x, (int) getpid());
int rc = fork();
if (rc < 0) // fork失败
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0) // child
{
printf("%d (pid:%d)\n", x, (int) getpid());
x = 1000;
}
else // parent
{
printf("%d (pid:%d)\n", x, (int) getpid());
x = 500;
}
printf("%d\n", x);
return 0;
}
// 运行结果:
// 100 (pid:19563)
// 100 (pid:19563)
// 500
// 100 (pid:19564)
// 1000

由此可见,在fork子进程之后修改主进程变量不会影响到子进程,要把它们理解成两个独立的进程,当然子进程的变量值全部继承于fork子进程之前的主进程。

2

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
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>
#include<string.h>
#include<sys/wait.h>

int main()
{
int fd = open("temp.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
int rc = fork();
if (rc < 0)
{
close(fd);
fprintf(stderr, "fork failed");
exit(1);
}
else if (rc == 0) // 子进程写入
{
char *s = "child write something!\n";
write(fd, s, strlen(s));
}
else // 主进程写入
{
char *s = "parent write something\n";
write(fd, s, strlen(s));
wait(NULL);
close(fd);
}
return 0;
}
// 运行结果
// child write something!
// parent write something!

两个进程都能对打开的文件进行修改。

3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
int rc = vfork();
if (rc < 0) // fork失败
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0) // child
printf("hello\n");
else // parent
printf("goodbye\n");
return 0;
}
// 运行结果
// hello
// goodbye

使用vfork创建子进程,可以优先执行子进程。

4

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int flag = 0;
const int MAX = 6;
int main()
{
char * s = "/bin/ls";
char * ss = "ls";
char * s2 = "/";
char * sv[] = { ss, s2, NULL };
for(flag = 0; flag < MAX; ++flag)
{
int rc = fork();
if (rc < 0) // fork失败
{
fprintf(stderr, "fork failed");
exit(1);
}
else if (rc == 0) // 子进程
{
switch(flag)
{
case 0:
execl(s, ss, s2, NULL);
break;
case 1:
execle(s, ss, s2, NULL);
break;
case 2:
execlp(s, s, s2, NULL);
break;
case 3:
execv(s, sv);
break;
case 4:
execvp(ss, sv);
break;
case 5:
execvpe(ss, sv);
break;
default: break;
}
}
else
wait(NULL);
}
return 0;
}
// 运行结果
// bin dev lib libx32 mnt root snap sys var
// boot etc lib32 lost+found opt run srv tmp
// cdrom home lib64 media proc sbin swapfile usr
// bin dev lib libx32 mnt root snap sys var
// boot etc lib32 lost+found opt run srv tmp
// cdrom home lib64 media proc sbin swapfile usr
// bin dev lib libx32 mnt root snap sys var
// boot etc lib32 lost+found opt run srv tmp
// cdrom home lib64 media proc sbin swapfile usr
// bin dev lib libx32 mnt root snap sys var
// boot etc lib32 lost+found opt run srv tmp
// cdrom home lib64 media proc sbin swapfile usr
// bin dev lib libx32 mnt root snap sys var
// boot etc lib32 lost+found opt run srv tmp
// cdrom home lib64 media proc sbin swapfile usr
// bin dev lib libx32 mnt root snap sys var
// boot etc lib32 lost+found opt run srv tmp
// cdrom home lib64 media proc sbin swapfile usr

依次调用了6个函数,可见都能实现最终效果。

5

第一个程序,在父进程中使用wait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0) // child
printf("I am child!(pid: %d)\n", (int)getpid());
else // parent
{
int wc = wait(NULL);
printf("I am parent!(wc: %d pid: %d)\n", wc, (int)getpid());
}
return 0;
}
// 运行结果
// I am child!(pid: 27378)
// I am parent!(wc: 27378 pid: 27377)

可以看到wait的返回值恰好是子进程的pid

第二个程序,在子进程中使用wait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0) // child
{
int wc = wait(NULL);
printf("I am child!(wc: %d pid: %d)\n", wc, (int)getpid());
}
else // parent
printf("I am parent!(pid: %d)\n", (int)getpid());
return 0;
}
// 运行结果
// I am parent!(pid: 28697)
// I am child!(wc: -1 pid: 28698)

可以看到运行结果依然是先运行主进程,再运行子进程,值得注意的是,wait返回值为-1。

6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0) // child
printf("I am child!(pid: %d)\n", (int)getpid());
else // parent
{
int wc = waitpid(NULL);
printf("I am parent!(wc: %d pid: %d)\n", wc, (int)getpid());
}
return 0;
}
// 运行结果
// I am child!(pid: 27378)
// I am parent!(wc: 27378 pid: 27377)

waitpid相比于wait的区别在于:
1 waitpid使我们可以等待指定的进程
2 waitpid提供了一个无阻塞的wait
3 waitpid支持工作控制

7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed");
exit(1);
}
else if (rc == 0)
{
close(STDOUT_FILENO);
printf("output child\n");
}
else
printf("output parent\n");
return 0;
}
// 运行结果
// output parent

子进程不会影响到主进程。

8

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
43
44
45
46
47
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
int pi[2];
int p = pipe(pi);
if(p < 0) // pipe failed
{
fprintf(stderr, "pipe failed");
exit(1);
}
int i = 0;
int rc[2];
char buf[256];
for(i = 0; i < 2; ++i)
{
rc[i] = fork();
if (rc[i] < 0)
{
fprintf(stderr, "fork failed");
exit(1);
}
else if (rc[i] == 0)
{
switch(i)
{
case 0:
dup2(pi[1], STDOUT_FILENO);
puts("child input");
break;
case 1:
dup2(pi[0], STDIN_FILENO);
gets(buf);
printf("child0 out (%s) in the child1\n", buf);
return 2;
}
break;
}
}
waitpid(rc[0], NULL, 0);
waitpid(rc[1], NULL, 0);
return 0;
}
// 运行结果
// child0 out (child input) in the child1

pipe创建一个管道,将两个进程连接到一起。
int wc = wait(NULL);
printf(“I am parent!(wc: %d pid: %d)\n”, wc, (int)getpid());
}
return 0;
}
// 运行结果
// I am child!(pid: 27378)
// I am parent!(wc: 27378 pid: 27377)

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
可以看到wait的返回值恰好是子进程的pid

第二个程序,在子进程中使用wait

```c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed\n");
exit(1);
}
else if (rc == 0) // child
{
int wc = wait(NULL);
printf("I am child!(wc: %d pid: %d)\n", wc, (int)getpid());
}
else // parent
printf("I am parent!(pid: %d)\n", (int)getpid());
return 0;
}
// 运行结果
// I am parent!(pid: 28697)
// I am child!(wc: -1 pid: 28698)

可以看到运行结果依然是先运行主进程,再运行子进程,值得注意的是,wait返回值为-1。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!