C POSIX命名管道(fifo)以非阻塞模式删除记录

C POSIX命名管道(fifo)以非阻塞模式删除记录,c,linux,posix,named-pipes,C,Linux,Posix,Named Pipes,我使用POSIX命名管道FIFO发送来自一个或多个线程的记录供另一个线程读取,只有一个线程进行读取。然而,100条记录中的第83条记录被简单地删除了。客户端内核调用write,返回值正确报告为记录720字节的长度,因此客户端writer内核确认记录已发送,但在调度程序锁定打开的情况下切换到gdb调试模式下的读卡器内核,我循环读取以前的几条记录,然后读取失败-管道中没有记录,即使客户端writer核心已确认写入 在Linux中,管道容量默认为65536字节。我假设管道内容在每次读取记录时减少1条记

我使用POSIX命名管道FIFO发送来自一个或多个线程的记录供另一个线程读取,只有一个线程进行读取。然而,100条记录中的第83条记录被简单地删除了。客户端内核调用write,返回值正确报告为记录720字节的长度,因此客户端writer内核确认记录已发送,但在调度程序锁定打开的情况下切换到gdb调试模式下的读卡器内核,我循环读取以前的几条记录,然后读取失败-管道中没有记录,即使客户端writer核心已确认写入

在Linux中,管道容量默认为65536字节。我假设管道内容在每次读取记录时减少1条记录,因此在删除第83条记录时,管道中大约有5条以前的记录,或3600字节,不足以填充管道

我在非阻塞模式下打开管道,因为当我在阻塞模式下打开管道时,两端都冻结了。根据处的手册页,必须在读取和写入数据之前打开FIFO的两端。通常,打开FIFO块,直到另一端也打开。我的问题是两端都堵塞了,不能再往前走了。它还说,在Linux下,在阻塞和非阻塞模式下,打开FIFO进行读写都会成功。POSIX未定义此行为

每一端的代码都很简单:

int64_t fifo_write(int fd, const void *buf, size_t count) {

    int status_write = write(fd, buf, count);

    return status_write; }

int64_t fifo_read(int fd, void *buf, size_t count) {

    int status_read = read(fd, buf, count); 

    return status_read; }
从我的NASM程序调用C函数:

mov rdi,[fifo_read_fd]
lea rsi,[fifo_buffer]
mov rdx,720
call fifo_read wrt ..plt

mov rdi,[fifo_write_fd]
mov rsi,[rbp-24]
mov rdx,720 ; bytes
push r11
push rcx
call fifo_write wrt ..plt
pop rcx
pop r11
我的问题是:

是什么原因导致记录丢失?它看起来不像管道容量,除非在读取每个记录时没有清空管道-即使所有83条记录也需要59760字节,低于Linux中的65K管道容量。这可能是由于非阻塞模式,但如果管道未满,则没有理由阻塞

如果两端都冻结了,每个都在等待另一个,那么如何在阻塞模式下打开两端?使用阻塞模式是否会有任何问题

我可以在读/写模式下打开两端,因为我的代码只从一端的一个或多个线程写入,而从另一端的一个线程读取。虽然POSIX未定义此行为,但在这种情况下,有没有任何原因不能在读/写模式下打开两端


除了上面提到的问题外,我没有发布任何其他关于这个问题的代码,因为我只是在寻找处理我描述的案例中记录丢失问题的最佳方法

您有多个写入程序使用一个FIFO发送720字节的消息。POSIX只需要写入512字节的管道,通常是原子的。这意味着较长的写操作可能会被其他线程的写操作交错并损坏

不管管道大小如何,管道都是流,它们没有消息的概念,这意味着您需要自己定义消息,而您的代码没有这样做。换句话说,当存在多个编写器时,您的读卡器代码不可能恢复单个消息


你可能会喜欢用a来代替。Unix数据报套接字中的每条消息都是一条原子消息,它在一个系统调用sendto和recvfrom中被完全写入和读取。

您有多个写入程序使用一个FIFO发送720字节的消息。POSIX只需要写入512字节的管道,通常是原子的。这意味着较长的写操作可能会被其他线程的写操作交错并损坏

不管管道大小如何,管道都是流,它们没有消息的概念,这意味着您需要自己定义消息,而您的代码没有这样做。换句话说,当存在多个编写器时,您的读卡器代码不可能恢复单个消息


你可能会喜欢用a来代替。Unix数据报套接字中的每条消息都是一条原子消息,它在一个系统调用sendto和recvfrom中被完全写入和读取。

尝试向struct添加属性,并检查是否能够发送更多数据。我正在读取和写入一条90个qwords-720字节的记录。int status\u read必须是ssize\u t status\u read。它不会解决您的问题,但消除所有潜在的错误是一个很好的练习。@Tony Tannonus-将它添加到什么结构中?我没有结构。我对阻塞打开时的两端阻塞[ed]症状感到好奇。第一个开启器线程应该只阻塞,直到它的补充线程与一个在打开时被阻塞的writer上的读卡器匹配为止,反之亦然,此时被阻塞的线程将恢复执行。在什么情况下都被阻止,并且是无限期的?尝试将属性添加到struct,并检查是否能够发送更多数据。我正在读取和写入一条90个qwords-720字节的记录。int status_read必须是ssize_t status_read。它不会解决您的问题,但消除所有潜在的错误是一个很好的练习。@Tony Tannonus-将它添加到什么结构中?我没有结构,我对机器人很好奇
h结束阻塞[ed]症状,阻塞打开。第一个开启器线程应该只阻塞,直到它的补充线程与一个在打开时被阻塞的writer上的读卡器匹配为止,反之亦然,此时被阻塞的线程将恢复执行。在什么情况下都会被阻塞,并且是无限期的?根据,在Linux上,PIPE_BUF是4096字节。但我将检查Unix数据报套接字-听起来性能更好。@RTC222添加了一个注释,说明PIPE_BUF与您的问题有点无关。我认为,如果记录大小为固定的720字节,则不需要分隔符。但是数据报套接字可以解决这个问题,而且听起来性能更好。@RTC222管道作为一个流意味着写可能写得更少,读可能读得更少。与Unix数据报套接字不同。他们应该至少写入PIPE_BUF,但是您的读取必须读取确切的消息大小,该大小必须小于或等于PIPE_BUF。这太麻烦了,使用Unix数据报套接字完全可以避免。FIFO是最古老的IPC之一,Unix套接字更加现代、灵活和强大。尤其是数据报Unix套接字,它允许原子地读写完整的消息。不过,我冒着重复我自己的风险。据我所知,在Linux上,PIPE_BUF是4096字节。但我将检查Unix数据报套接字-听起来性能更好。@RTC222添加了一个注释,说明PIPE_BUF与您的问题有点无关。我认为,如果记录大小为固定的720字节,则不需要分隔符。但是数据报套接字可以解决这个问题,而且听起来性能更好。@RTC222管道作为一个流意味着写可能写得更少,读可能读得更少。与Unix数据报套接字不同。他们应该至少写入PIPE_BUF,但是您的读取必须读取确切的消息大小,该大小必须小于或等于PIPE_BUF。这太麻烦了,使用Unix数据报套接字完全可以避免。FIFO是最古老的IPC之一,Unix套接字更加现代、灵活和强大。尤其是数据报Unix套接字,它允许原子地读写完整的消息。不过,我冒着重复自己的风险。