当写入速度快于 reader 时 C FIFO 崩溃
C FIFO crashes when writer goes faster than reader
我有一个使用 fork 的父进程和子进程,它们使用 FIFO 管道进行通信。当编写器进程(父进程)比 reader 进程(子进程)运行得更快时,该程序有时会运行,有时会崩溃。
下面的代码是我目前的代码。
void writeprocess(char* text);
void readprocess(void);
#define FIFO_NAME "MYTESTFIFO"
#define MAX 200
int main(int argc, const char * argv[]) {
pid_t pid;
pid = fork();
if(pid==0){
printf("Started child process.\n");
mkfifo(FIFO_NAME, 0666);
readprocess();
printf("Child process finished.\n");
exit(EXIT_SUCCESS);
}
else{
printf("Started parent process.\n");
mkfifo(FIFO_NAME, 0666);
writeprocess("Message 1");
writeprocess("Message 2");
writeprocess("Message 3");
writeprocess("Message 4");
writeprocess("terminate");
printf("Waiting for child process to finish.\n");
int returnStatus;
waitpid(pid, &returnStatus, 0);
printf("Parent process also finished.\n");
exit(EXIT_SUCCESS);
}
}
void writeprocess(char* text){
FILE *fp;
char *send_buf;
fp = fopen(FIFO_NAME, "w");
asprintf( &send_buf, "%s\n", text);
if ( fputs( send_buf, fp ) == EOF )
{
fprintf( stderr, "Error writing data to fifo\n");
exit( EXIT_FAILURE );
}
printf("Message send: %s", send_buf);
free( send_buf );
fclose(fp);
}
void readprocess(){
sleep(1);
FILE *fp;
char *str_result = NULL;
char recv_buf[MAX];
int stringdifference = 1;
while (stringdifference)
{
fp = fopen(FIFO_NAME, "r");
str_result = fgets(recv_buf, MAX, fp);
if ( str_result != NULL )
{
printf("Message received: %s", recv_buf);
}
fclose( fp );
stringdifference = strncmp(str_result, "terminate", 9);
}
}
当编写器写入 FIFO 管道的速度快于 reader 的读取速度时,我收到一个退出错误并显示以下消息:"Terminated due to signal 13"。如何在让我的程序 运行 保持完整性能的同时避免这种情况发生?
我确实希望父进程能够结束进程,我必须继续使用 FIFO 管道工作。
信号 13 是 SIGPIPE。发生这种情况是因为没有人从 FIFO 中读取数据。
如果当前没有打开 FIFO 以供读取的进程,则无法写入 FIFO。如果您尝试这样做,您的进程将获得 SIGPIPE(可以忽略,将其变成 EPIPE...但无论哪种方式,它都会失败)。
正确处理此问题的一种方法:
在父级中创建 FIFO。
分叉。
在写入进程中,打开写入。这将阻塞,直到 reader 打开它。保持打开状态。
在reader进程中,打开写入。这将阻塞,直到作者打开它。保持打开状态。
When the writer writes faster to the FIFO pipe than the reader can read, I get an exit error with the following message: "Terminated due to signal 13".
您错误地描述了问题的性质。正如您的其他答案已经观察到的那样,信号 13 是 SIGPIPE
,如果您尝试写入没有 readers.
的管道,则会传送该信号
通常有一些(有限的)保护来防止使用 FIFO 进入这种情况,因为打开 FIFO 的一端会阻塞,直到另一端也被打开。因此,如果一个进程成功打开了一个 FIFO,它就知道最初有另一个进程打开了另一端。写端打开的那一个可以期望写成功的可能性很高(但不一定没有阻塞)。然而,一旦最后一个 reader 关闭 FIFO,进一步的写入尝试将导致 SIGPIPE
被传递给写入器。当然,如果相同的或新的 reader 打开 FIFO,则允许写入恢复——这对于 FIFO 是可能的,但对于普通管道则不行。
所以问题不在于reader没有跟上,而是它不断打开和关闭FIFO。这创建了一个竞争条件,因为有多个间隔,如果 writer 尝试写入,它将在其中引发 SIGPIPE
。由于写入器 也 重复打开和关闭 FIFO,因此要接收 SIGPIPE
,写入器必须在 reader 关闭 FIFO 之前重新打开它上一条消息,但这并不意味着作者的速度超过 reader。 reader 无法在作者完成写入之前完成给定消息的阅读,因此他们的行为是交错的。作者在关闭 FIFO 和重新打开它之间没有做任何其他事情,因此它有时会在 reader 关闭之前重新打开也就不足为奇了。
解决方案很简单:让每个进程持续打开管道,直到完成与另一个进程的通信。打开和关闭每条消息没有好处,但有很多缺点。但是,对于您的特定用途,将作者的流置于行缓冲模式可能会有所帮助(setvbuf()
;默认情况下将是完全缓冲的)。
我有一个使用 fork 的父进程和子进程,它们使用 FIFO 管道进行通信。当编写器进程(父进程)比 reader 进程(子进程)运行得更快时,该程序有时会运行,有时会崩溃。
下面的代码是我目前的代码。
void writeprocess(char* text);
void readprocess(void);
#define FIFO_NAME "MYTESTFIFO"
#define MAX 200
int main(int argc, const char * argv[]) {
pid_t pid;
pid = fork();
if(pid==0){
printf("Started child process.\n");
mkfifo(FIFO_NAME, 0666);
readprocess();
printf("Child process finished.\n");
exit(EXIT_SUCCESS);
}
else{
printf("Started parent process.\n");
mkfifo(FIFO_NAME, 0666);
writeprocess("Message 1");
writeprocess("Message 2");
writeprocess("Message 3");
writeprocess("Message 4");
writeprocess("terminate");
printf("Waiting for child process to finish.\n");
int returnStatus;
waitpid(pid, &returnStatus, 0);
printf("Parent process also finished.\n");
exit(EXIT_SUCCESS);
}
}
void writeprocess(char* text){
FILE *fp;
char *send_buf;
fp = fopen(FIFO_NAME, "w");
asprintf( &send_buf, "%s\n", text);
if ( fputs( send_buf, fp ) == EOF )
{
fprintf( stderr, "Error writing data to fifo\n");
exit( EXIT_FAILURE );
}
printf("Message send: %s", send_buf);
free( send_buf );
fclose(fp);
}
void readprocess(){
sleep(1);
FILE *fp;
char *str_result = NULL;
char recv_buf[MAX];
int stringdifference = 1;
while (stringdifference)
{
fp = fopen(FIFO_NAME, "r");
str_result = fgets(recv_buf, MAX, fp);
if ( str_result != NULL )
{
printf("Message received: %s", recv_buf);
}
fclose( fp );
stringdifference = strncmp(str_result, "terminate", 9);
}
}
当编写器写入 FIFO 管道的速度快于 reader 的读取速度时,我收到一个退出错误并显示以下消息:"Terminated due to signal 13"。如何在让我的程序 运行 保持完整性能的同时避免这种情况发生?
我确实希望父进程能够结束进程,我必须继续使用 FIFO 管道工作。
信号 13 是 SIGPIPE。发生这种情况是因为没有人从 FIFO 中读取数据。
如果当前没有打开 FIFO 以供读取的进程,则无法写入 FIFO。如果您尝试这样做,您的进程将获得 SIGPIPE(可以忽略,将其变成 EPIPE...但无论哪种方式,它都会失败)。
正确处理此问题的一种方法:
在父级中创建 FIFO。
分叉。
在写入进程中,打开写入。这将阻塞,直到 reader 打开它。保持打开状态。
在reader进程中,打开写入。这将阻塞,直到作者打开它。保持打开状态。
When the writer writes faster to the FIFO pipe than the reader can read, I get an exit error with the following message: "Terminated due to signal 13".
您错误地描述了问题的性质。正如您的其他答案已经观察到的那样,信号 13 是 SIGPIPE
,如果您尝试写入没有 readers.
通常有一些(有限的)保护来防止使用 FIFO 进入这种情况,因为打开 FIFO 的一端会阻塞,直到另一端也被打开。因此,如果一个进程成功打开了一个 FIFO,它就知道最初有另一个进程打开了另一端。写端打开的那一个可以期望写成功的可能性很高(但不一定没有阻塞)。然而,一旦最后一个 reader 关闭 FIFO,进一步的写入尝试将导致 SIGPIPE
被传递给写入器。当然,如果相同的或新的 reader 打开 FIFO,则允许写入恢复——这对于 FIFO 是可能的,但对于普通管道则不行。
所以问题不在于reader没有跟上,而是它不断打开和关闭FIFO。这创建了一个竞争条件,因为有多个间隔,如果 writer 尝试写入,它将在其中引发 SIGPIPE
。由于写入器 也 重复打开和关闭 FIFO,因此要接收 SIGPIPE
,写入器必须在 reader 关闭 FIFO 之前重新打开它上一条消息,但这并不意味着作者的速度超过 reader。 reader 无法在作者完成写入之前完成给定消息的阅读,因此他们的行为是交错的。作者在关闭 FIFO 和重新打开它之间没有做任何其他事情,因此它有时会在 reader 关闭之前重新打开也就不足为奇了。
解决方案很简单:让每个进程持续打开管道,直到完成与另一个进程的通信。打开和关闭每条消息没有好处,但有很多缺点。但是,对于您的特定用途,将作者的流置于行缓冲模式可能会有所帮助(setvbuf()
;默认情况下将是完全缓冲的)。