我编写了一个简单的脚本(取自教程(,该脚本将数据写入子进程中管道的一端,并从父进程中管道的另一端读取数据:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int mypipefd[2];
int ret;
char buf[20];
ret = pipe(mypipefd);
if (ret == -1) {
printf("Pipe failed.n");
exit(1);
}
if ((pid = fork()) == -1) {
printf("Fork failed.n");
exit(1);
} else if (pid == 0) {
printf("Child process.n");
char msg[] = "Hello there!";
write(mypipefd[1], msg, strlen(msg) + 1);
} else {
printf("Parent process.n");
read(mypipefd[0], buf, 15);
printf("Buf: %sn", buf);
}
return 0;
}
这工作正常并输出我期望的结果:
Parent process.
Child process.
Buf: Hello there!
[ project ] $
然后,随着我对代码越来越熟悉,我想知道为什么我们需要使用mypipefd[2]
和pipe()
来实现这个目标,或者mypipefd[1]
本身是否有效。 所以我用下面的代码尝试了一下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int my_array[1];
char buf[20];
if ((pid = fork()) == -1) {
printf("Fork failed.n");
exit(1);
} else if (pid == 0) {
printf("Child process.n");
char msg[] = "Hello there!n";
write(my_array[0], msg, strlen(msg) + 1);
} else {
// wait(NULL);
printf("Parent process.n");
read(my_array[0], buf, 15);
printf("Buf: %sn", buf);
}
return 0;
}
此代码输出相同的文本,但在完成打印后挂起。
Parent process.
Child process.
Buf: Hello there!
这次没有提示。 我什至尝试取消注释该调用wait(NULL)
,因为根本原因是父进程和子进程之间的冲突。 没有这样的运气。
这是怎么回事? 为什么我无法在不挂起程序的情况下以这种方式读取和写入一长度的数组? 编译器到底卡在什么地方?
管道,在计算机和现实生活中,都有两端。就像现实生活中的管道一样,数据从管道的一端(写入端(流向另一端(读取端(。
pipe
函数通过将这两个端点写入两个文件描述符的数组来为您提供这两个端点。该对的第一个元素是只读的,第二个元素是只写的。
pipe(( 函数接受一个 2 个整数的数组作为输入参数。
#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
然后,它会生成一个新的管道对象,并使用文件描述符初始化 pipefd 数组以进行读写操作。
您尝试做的是使用一些任意的、未初始化的整数(或文件描述符(调用 read(( 和 write((。这意味着操作系统没有分配管道对象,也没有为您提供与 read(( 和 write(( 一起使用的文件描述符(管道的 API(。
这(使用未初始化的文件描述符调用 read(( 或 write(((将导致"未定义的行为"。
"我发现'未定义的行为'的一个很好的工作定义是"对我有用,对你有用,在开发和QA期间工作,但在你最重要的客户面前爆炸"---斯科特·迈耶斯