c语言 - 为什么在程序中"cat" FIFO 特殊文件或创建 FIFO 特殊文件后没有出现 shell 提示符?



我正在学习Linux中的命名管道,并编写以下程序进行尝试。

以下程序创建一个名为"test.fifo"的FIFO特殊文件,然后创建两个子进程以从该命名管道读取和写入。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <wait.h>
int main() {
pid_t pid[2];
// Create FIFO special file
mkfifo("test.fifo", 0644);
pid[0] = fork();
if (pid[0] < 0) {
printf("Fail to fork child process #0n");
return 1;
} else if (pid[0] == 0) {
// Open FIFO special file in read mode
int in = open("test.fifo", O_RDONLY);
// Read data
char buf[256];
read(in, buf, 256);
printf("Child process #0 received: %sn", buf);
// Close pipe
close(in);
return 0;
}
pid[1] = fork();
if (pid[1] < 0) {
printf("Fail to fork child process #1n");
return 1;
} else if (pid[1] == 0) {
// Open FIFO special file in write mode
int out = open("test.fifo", O_WRONLY);
// Write data
char buf[256] = {0};
strcpy(buf, "Hello world");
write(out, buf, 256);
// Close pipe
close(out);
return 0;
}
return 0;
}

有时此程序正常运行。但有时在这个程序运行后,我的 shell 提示符会消失。

MyUserName@MyHostName:~$ ./a.out
MyUserName@MyHostName:~$ Child process #0 received: Hello world
(This is an empty line, no shell prompt occurs)

我尝试在空行中键入并运行命令ls,并且该命令有效。所以看起来程序已经成功退出,只是没有出现shell提示。

如果我运行命令cat test.fifo也会发生同样的事情。

MyUserName@MyHostName:~$ cat test.fifo
(This is an empty line, no shell prompt occurs)

发生了什么,为什么会这样?

由于父程序没有wait(2)让子程序完成,当它exit(2)时(在 main 的最后一return 0;上),shell 会显示提示。 但是您无法控制(甚至不知道)子项是否已完成打印其输出,因此 shell 提示符可能被其中一个子项的输出覆盖。 但是 shell 总是输出提示,但由于它不遵循新行(光标保持在同一行中),因此某些内容可能会被子项的输出覆盖。

尝试将以下内容放在最后一个return 0;之前:

wait(NULL);
wait(NULL); /* as you did two fork()s you can make up to two wait()s */

然后,程序终止将与子项同步。

感谢您的所有评论!

就像Charles Duffy说的,shell提示符已经被打印出来了——它是./a.out调用之后的那个。我忘了在父进程中使用wait()。因此,如果父进程在子进程之前退出,则 shell 提示符将在"子进程 #0..."内容之前打印。

至于cat test.fifo,我在描述中犯了一个错误。如果我运行cat test.fifo,不仅不会出现 shell 提示符,而且如果我在空行上键入并运行它,ls命令也无法工作。这是因为cat命令尝试在读取模式下打开 FIFO 特殊文件,但没有进程尝试在写入模式下打开 FIFO 特殊文件。

从 https://linux.die.net/man/7/fifo 我们知道,"在传递数据之前,必须在两端(读取和写入)打开FIFO。通常,打开FIFO块,直到另一端也打开。因此,cat test.fifo命令实际上已被阻止并且尚未退出,因此不会发生 shell 提示符。

最新更新