Skip to content

Commit

Permalink
update Chapter-15
Browse files Browse the repository at this point in the history
  • Loading branch information
MeiK2333 committed Jul 17, 2018
1 parent 6783bec commit 6e582dc
Show file tree
Hide file tree
Showing 11 changed files with 726 additions and 20 deletions.
38 changes: 19 additions & 19 deletions Chapter-15/15.4.4.c
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
#include "apue.h"

int main() {
int int1, int2;
char line[MAXLINE];
int int1, int2;
char line[MAXLINE];

if (setvbuf(stdin, NULL, _IOLBF, 0) != 0) {
err_sys("setvbuf error");
}
if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) {
err_sys("setvbuf error");
}
if (setvbuf(stdin, NULL, _IOLBF, 0) != 0) {
err_sys("setvbuf error");
}
if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) {
err_sys("setvbuf error");
}

while (fgets(line, MAXLINE, stdin) != NULL) {
if (sscanf(line, "%d%d", &int1, &int2) == 2) {
if (printf("%d\n", int1 + int2) == EOF) {
err_sys("printf error");
}
} else {
if (printf("invalid args\n") == EOF) {
err_sys("printf error");
}
while (fgets(line, MAXLINE, stdin) != NULL) {
if (sscanf(line, "%d%d", &int1, &int2) == 2) {
if (printf("%d\n", int1 + int2) == EOF) {
err_sys("printf error");
}
} else {
if (printf("invalid args\n") == EOF) {
err_sys("printf error");
}
}
}
}
exit(0);
exit(0);
}
184 changes: 183 additions & 1 deletion Chapter-15/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,186 @@ update 998 from parent
update 999 from child
```

可以很方便的实现在父子进程之间共享内存
可以很方便的实现在父子进程之间共享内存

## 课后习题

### 15.1

**在图 15-6 的程序中, 在父进程代码的末尾删除 waitpid 前的 close, 结果将如何?**
在文件没有读取结束的时候表现相同, 在读取到文件末尾的时候, 因为管道未关闭, 分页程序会一直阻塞读取标准输入.

### 15.2

**在图 15-6 的程序中, 在父进程代码的末尾删除 waitpid, 结果将如何?**
分页程序输出的内容比文件的内容少一行, 因为父进程输出完所有的内容之后终止, 父进程终止时管道的读端自动关闭, 这时子进程正在等待输出, 因此父进程比子进程领先一个缓冲区的内容.

### 15.3

**如果 `popen` 函数的参数是一个不存在的命令, 会造成什么结果? 编写一段小程序对此进行测试.**
因为执行了 shell, 所有 `popen` 返回一个文件指针. 但是 shell 不能执行不存在的命令, 因此在标准错误上打印下面信息后终止:

```shell
sh: line 1: ./a.out: No such file or directory
```

其退出状态为 127(该值取决于 shell 的类型). `pclose` 返回该命令的终止状态, 这如同从 `waitpid` 返回一样.

### 15.4

**在图 15-18 的程序中, 删除信号处理程序, 执行该进程, 然后终止子进程. 输入一行输入后, 怎样才能说明父进程是由 SIGPIPE 终止的?**

当父进程终止时, 用 shell 看它的终止状态. 打印的结果是 128 加上信号编号

```shell
$ ./a.out
1 2
3
^C
$ echo $?
130
```

### 15.5

**在图 15-18 的程序中, 用标准 I/O 库代替管道读、写的 read 和 write.**
使用 `fdopen` 关联管道描述符和标准 I/O 流, 然后将流设置为行缓冲的

```shell
gcc 15.4.c -lapue -o add2
$ gcc p5.c -lapue
$ ./a
a.out add2
$ ./a.out
1 2
3
3 4
7
^C
```

### 15.6

**POSIX.1 加入 `waitpid` 函数的理由之一是, POSIX.1 之前的大多数系统不能处理下面的代码.**

```C
if ((fd = popen("/bin/true", "r")) == NULL) {
// ...
}
if ((rc = system("sleep 100")) == -1) {
// ...
}
if (pclose(fp) == -1) {
// ...
}
```

**若这段代码中不使用 `waitpid` 函数会怎样? 用 `wait` 代替呢?**
`system` 函数调用了 `wait` , 终止的第一个子进程是由 `popen` 产生的. 因为该子进程不是 `system` 创建的, 所以它将再次调用 `wait` 并一直阻塞到 `sleep` 完成. 然后 `system` 返回. 当 `pclose` 调用 `wait` 时, 由于没有子进程可等待所以返回出错, 导致 `pclose` 也返回出错

### 15.7

**当一个管道被写者关闭后, 解释 `select``poll` 是如何处理改管道的输入描述符的. 为了确定答案是否正确, 编两个小测试程序, 一个用 `select`, 另一个用 `poll`.**

### 15.8

**如果 `popen`*type* 为 "r" 执行 cmdstring, 并将结果写到标准错误输出, 结果会怎样?**
子进程想标准错误写的内容也会在父进程的标准错误中出现, 只要在 cmdstring 中包含 shell 重定向 `2>&1` , 就可以将标准错误发回给父进程.

### 15.9

**既然 `popen` 函数能使 shell 执行它的 cmdstring 参数, 那么 cmdstring 终止时会产生什么结果?(提示: 画出与此相关的所有进程.)**
`popen` 函数 `fork` 一个子进程, 子进程执行 shell , 然后 shell 再调用 `fork` , 最后由 shell 的子进程执行命令串. 当 cmdstring 终止时, shell 恰好在等待该事件. 然后 shell 退出, 而这一事件又是 `pclose` 中的 `waitpid` 所等待的.

### 15.10

**POSIX.1 特别声明没有定义为读写而打开 FIFO. 虽然大多数 UNIX 系统允许读写 FIFO, 但是请用非阻塞方法实现为读写而打开FIFO.**
解决的办法是打开(open) FIFO 两次: 一次读; 一次写.

### 15.11

**除非文件包含敏感数据或机密数据, 否则允许其他用户读文件不会造成损害. 但是, 如果一个恶意进程读取了被一个服务器进程和几个客户进程使用的消息队列中的一条消息后, 会产生什么后果? 恶意进程需要知道哪些信息就可以读消息队列?**
随意读取现行队列中的消息会干扰客户进程=服务器进程协议, 导致丢失客户进程请求或者服务器进程的响应. 只要知道队列的标识符或者该队列允许所有的用户读, 进程就可以读队列.

### 15.12

**编写一段程序完成下面的工作. 执行一个循环 5 次, 在每次循环中, 创建一个消息队列, 打印该队列的标识符, 然后删除队列. 接着再循环 5 次, 在每次循环中利用键 IPC_PRIVATE 创建消息队列, 并将一条消息放在队列中. 程序终止后用 ipcs(1) 查看消息队列. 解释队列标识符的变化.**
执行 p12.c

```shell
$ sudo ./a.out
id = 1310720
id = 1376256
id = 1441792
id = 1507328
id = 1572864


id = 1638400
id = 524289
id = 131074
id = 131075
id = 131076
$ ipcs
IPC status from <running system> as of Tue Jul 17 13:02:04 CST 2018
T ID KEY MODE OWNER GROUP
Message Queues:
q 1638400 0x00000000 ----------- root wheel
q 524289 0x00000000 ----------- root wheel
q 131074 0x00000000 ----------- root wheel
q 131075 0x00000000 ----------- root wheel
q 131076 0x00000000 ----------- root wheel

T ID KEY MODE OWNER GROUP
Shared Memory:

T ID KEY MODE OWNER GROUP
Semaphores:

```

### 15.13

**描述如何在共享存储段中建立一个数据对象的链接列表. 列表指针如何存储?**
由于服务器进程和各客户进程可能会将段连接到不同的地址, 所以在共享存储段中绝不会存储实际物理地址. 相反, 当在共享存储段中建立链表时, 链表指针的值会设置为共享存储段内另一对象的偏移量. 偏移量为所指对象的实际地址减去共享存储段的起始地址.

### 15.14

**画出图 15-33 中程序运行时下列值随时间变化的曲线图: 父进程和子进程中的变量 i、共享存储区中的长整型值以及 `update` 函数的返回值. 假设子进程在 `fork` 后先执行.**

| 父进程的 i 设置成 | 子进程的 i 设置成 | 共享值设置成 | update 返回 | 注释 |
|--|--|--|--|--|
| | | 0 | | 由 mmap 初始化 |
| | 1 | | | 子进程先运行, 然后被阻塞 |
| 0 | | | | 父进程先运行 |
| | | 1 | | |
| | | | 0 | 然后父进程被阻塞 |
| | | 2 | | 子进程继续 |
| | | | 1 | |
| | 3 | | | 然后子进程被阻塞 |
| 2 | | | | 父进程继续 |
| | | 3 | | |
| | | | 2 | 然后父进程被阻塞 |
| | | 4 | | |
| | | | 3 | |
| | 5 | | | 然后子进程被阻塞 |
| 4 | | | | 父进程继续 |

### 15.15

**使用 15.9 节中的 XSI 共享存储函数代替共享存储映射区, 改写图 15-33 中的程序.**
[p15.c](p15.c), 将之前的 `mmap` 一句改为了 `shmget``shmat` 函数.

### 15.16

**使用 15.8 节中的 XSI 信号量函数改写图 15-33 中的程序, 实现父进程与子进程间的交替.**
[p16.c](p16.c), 每次申请 i 个资源, 释放 i + 1 个, 从而让父子进程交替执行.

### 15.17

**使用建议性记录锁改写图 15-33 中的程序, 实现父进程与子进程间的交替.**

### 15.18

**使用 15.10 节中的 POSIX 信号量函数改写 15-33 中的程序, 实现父进程与子进程间的交替.**
[p18.c](p18.c), 通过两个信号量, 实现父子进程的交替.
69 changes: 69 additions & 0 deletions Chapter-15/p1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <sys/wait.h>
#include "apue.h"

#define DEF_PAGER "/bin/more"

int main(int argc, char *argv[]) {
int n;
int fd[2];
pid_t pid;
char *pager, *argv0;
char line[MAXLINE];
FILE *fp;

if (argc != 2) {
err_quit("usage: a.out <pathname>");
}

if ((fp = fopen(argv[1], "r")) == NULL) {
err_sys("can't open %s", argv[1]);
}
if (pipe(fd) < 0) {
err_sys("pipe error");
}

if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid > 0) {
close(fd[0]);

while (fgets(line, MAXLINE, fp) != NULL) {
n = strlen(line);
if (write(fd[1], line, n) != n) {
err_sys("write error to pipe");
}
}
if (ferror(fp)) {
err_sys("fgets error");
}

// close(fd[1]);

if (waitpid(pid, NULL, 0) < 0) {
err_sys("waitpid error");
}
exit(0);
} else {
close(fd[1]);
if (fd[0] != STDIN_FILENO) {
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
err_sys("dup2 error to stdin");
}
close(fd[0]);
}

if ((pager = getenv("PAGER")) == NULL) {
pager = DEF_PAGER;
}
if ((argv0 = strrchr(pager, '/')) != NULL) {
argv0++;
} else {
argv0 = pager;
}

if (execl(pager, argv0, (char *)0) < 0) {
err_sys("excel error for %s", pager);
}
}
exit(0);
}
21 changes: 21 additions & 0 deletions Chapter-15/p10.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "apue.h"
#include <fcntl.h>

#define FIFO "temp.fifo"

int main() {
int fdread, fdwrite;

unlink(FIFO);
if (mkfifo(FIFO, FILE_MODE) < 0) {
err_sys("mkfifo error");
}
if ((fdread = open(FIFO, O_RDONLY | O_NONBLOCK)) < 0) {
err_sys("open error for reading");
}
if ((fdwrite = open(FIFO, O_WRONLY)) < 0) {
err_sys("open error for writing");
}
clr_fl(fdread, O_NONBLOCK);
exit(0);
}
37 changes: 37 additions & 0 deletions Chapter-15/p12.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>

int main() {
int i, id;
char *hello = "Hello World!\n";
for (i = 0; i < 5; i++) {
if ((id = msgget(0, IPC_CREAT)) == -1) {
printf("msgget error\n");
exit(1);
}
printf("id = %d\n", id);
if (msgctl(id, IPC_RMID, NULL) == -1) {
printf("msgctl IPC_RMID error\n");
exit(1);
}
}

printf("\n\n");

for (i = 0; i < 5; i++) {
if ((id = msgget(IPC_PRIVATE, 0)) == -1) {
printf("msgget error\n");
exit(1);
}
printf("id = %d\n", id);
if (msgsnd(id, hello, 0, IPC_NOWAIT) == -1) {
printf("%s\n", strerror(errno));
printf("msgsnd error\n");
exit(1);
}
}
exit(0);
}
Loading

0 comments on commit 6e582dc

Please sign in to comment.