Bài 43.126 phút đọc
pipe giữa cha và con
Sau bài này bạn sẽ làm được
- Tạo pipe và truyền dữ liệu giữa cha và con
- Giải thích vì sao phải đóng đầu không dùng
- Nhận ra khi nào read treo vì thiếu EOF
- Kể bốn đặc điểm của pipe
Sau khi fork, cha và con là hai không gian địa chỉ riêng, không thấy biến của nhau. pipe là cách đơn giản nhất để chúng nói chuyện: một ống một chiều để truyền byte giữa hai tiến trình họ hàng.
#pipe
Chữ ký
#include <unistd.h>
int pipe(int fd[2]);
/* Tao mot ong, dat hai mo ta tep vao mang:
fd[0] = dau DOC
fd[1] = dau GHI
Ghi vao fd[1] -> doc ra o fd[0]. Mot chieu.
Tra ve 0 thanh cong, -1 loi. */Pipe
Một bộ đệm trong nhân với hai đầu: một đầu ghi, một đầu đọc. Byte ghi vào đầu ghi được đọc ra ở đầu đọc theo đúng thứ tự. Nó một chiều, và chỉ dùng được giữa các tiến trình có quan hệ họ hàng, vì hai đầu được truyền qua
fork. Tien trinh CHA Tien trinh CON
fd[1] --ghi--> [ ong trong nhan ] --doc--> fd[0]
/* Truoc fork, cha goi pipe() de tao ong. Sau fork, con THUA
HUONG ca hai dau (fd[0] va fd[1]) tu cha, nen ca hai deu truy
cap duoc ong. Do la ly do pipe chi noi duoc giua cha con (hoac
anh em cung cha): hai dau ong phai duoc truyen qua fork. Muon
noi giua tien trinh BAT KY thi dung named pipe hoac socket
(Bai 43.3). */#Cha gửi, con nhận
pipe_demo.c
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void) {
int fd[2];
if (pipe(fd) < 0) { perror("pipe"); return 1; }
pid_t pid = fork();
if (pid == 0) {
/* CON: chi DOC */
close(fd[1]); /* DONG dau ghi, quan trong */
char buf[256];
ssize_t n = read(fd[0], buf, sizeof buf - 1);
if (n > 0) { buf[n] = '\0'; printf("Con nhan: %s\n", buf); }
close(fd[0]);
_exit(0);
} else {
/* CHA: chi GHI */
close(fd[0]); /* DONG dau doc */
const char *msg = "Xin chao tu tien trinh cha";
write(fd[1], msg, strlen(msg));
close(fd[1]); /* dong -> con nhan EOF */
wait(NULL);
}
return 0;
}terminal
gcc pipe_demo.c -o pipe_demo && ./pipe_demo
Con nhan: Xin chao tu tien trinh cha
#Quy tắc sống còn
Quên đóng đầu ghi ở con
if (pid == 0) {
/* con doc, nhung QUEN close(fd[1]) */
char buf[256];
read(fd[0], buf, sizeof buf); /* TREO: con van giu dau ghi mo,
read khong bao gio thay EOF */
}
Đóng đầu không dùng
if (pid == 0) {
close(fd[1]); /* dong dau ghi TRUOC khi doc */
char buf[256];
ssize_t n = read(fd[0], buf, sizeof buf); /* nhan EOF dung cach */
close(fd[0]);
}
#Bốn đặc điểm
| Đặc điểm | Chi tiết |
|---|---|
| Một chiều | Chỉ ghi một đầu, đọc đầu kia; muốn hai chiều cần hai pipe |
| Chỉ họ hàng | Hai đầu truyền qua fork, nên chỉ giữa cha con hoặc anh em |
| Dung lượng hữu hạn | Khoảng 64 KB trên Linux; write chặn khi đầy |
| Dòng byte | Không bảo toàn ranh giới thông điệp, như TCP (Bài 46.5) |
Tự làm thử
- Viết chương trình cha gửi một chuỗi qua pipe, con nhận và in.
- Quên
close(fd[1])ở con và quan sát con treo ởread. - Cha gửi một mảng số, con tính tổng rồi gửi kết quả về, dùng hai pipe.
- Ghi hơn 64 KB vào pipe trước khi con đọc và quan sát cha treo ở
write. - Gửi hai thông điệp liên tiếp và chứng minh bên đọc có thể nhận gộp.
- Đo dung lượng pipe trên máy bạn bằng cách ghi tới khi
writechặn.
Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.
Tóm tắt
pipetạo một ống một chiều với đầu đọcfd[0]và đầu ghifd[1]; gọi trướcfork.- Mỗi bên phải đóng đầu không dùng; nếu con giữ đầu ghi mở,
readkhông bao giờ thấy EOF và treo. readthấy EOF chỉ khi mọi đầu ghi đã đóng; ghi vào ống không còn ai đọc sinhSIGPIPE.- Pipe chặn khi đầy hoặc rỗng, là cơ chế đồng bộ tự nhiên; ghi lớn phải đọc song song.
- Pipe một chiều, chỉ giữa họ hàng, dung lượng hữu hạn, và là dòng byte không giữ ranh giới.