当写入器速度快于读取器时,C FIFO 崩溃

标签 c pipe fifo

我有一个使用 fork 的父进程和子进程,它们使用 FIFO 管道进行通信。当写入进程(父进程)比读取进程(子进程)运行得更快时,程序有时会工作,有时会崩溃。

以下代码是我目前拥有的代码。

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 管道的速度比读取器读取的速度快时,我会收到退出错误,并显示以下消息:“由于信号 13 而终止”。如何避免这种情况发生,同时保持程序以最佳性能运行?

我确实希望父进程能够结束该进程,并且我必须继续使用 FIFO 管道工作。

最佳答案

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,如果您尝试写入没有读取器的管道,则会传递该信号。

通常有一些(有限的)保护措施来防止 FIFO 进入这种情况,即打开 FIFO 的一端会阻塞,直到另一端也打开为止。因此,如果一个进程成功打开 FIFO,它就知道最初有另一个进程的另一端打开。写入端打开的一方可以预期写入成功的可能性很高(但不一定不会阻塞)。然而,一旦最后一个读取器关闭 FIFO,进一步尝试写入它就会导致将 SIGPIPE 传递给写入器。当然,如果同一个或新的读取器打开 FIFO,则允许恢复写入——这对于 FIFO 来说是可能的,但对于普通管道来说是不可能的。

所以问题不在于读取器没有跟上,而在于它不断地打开和关闭 FIFO。这会产生竞争条件,因为写入器在尝试写入时会在多个时间间隔内引发 SIGPIPE。由于写入器重复打开和关闭 FIFO,因此要接收 SIGPIPE,写入器必须在读取器在收到上一条消息后关闭 FIFO 之前重新打开 FIFO,但是这并不意味着作者超越了读者。读者无法在作者写完之前读完给定的消息,因此他们的行为是交错的。在关闭 FIFO 和重新打开它之间,写入器没有执行任何其他操作,因此有时在读取器关闭之前重新打开它也就不足为奇了。

解决方案很简单:让每个进程保持管道持续打开,直到完成与其他进程的通信。每条消息的打开和关闭没有任何好处,但有很多缺点。但是,对于您的特定用途,将编写器的流置于行缓冲模式( setvbuf() ;默认情况下将是完全缓冲的)可能会有所帮助。

关于当写入器速度快于读取器时,C FIFO 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57294675/

相关文章:

c - 具体的C fifo实现困惑

c++ - 如何通过 fifo 发送结构

将数组中存储的 char 类型转换为 int 变量

c - 在 C 中,我无法将字符串数组的单个元素复制到另一个字符串

sorting - 带有对象数组的 Angular2 排序管道

linux - 在子目录中查找特定字符串并按修改日期对顶级目录排序

具有多个 fifo 的 Linux tee 命令。 fifo block 三通

C Printf 将 %p 作为 system()

c - 提高SQLite每秒INSERT的性能?

python - Popen 包含需要对所有输出说是的命令