POSIX 命名管道 (fifo) 在非阻塞模式下删除记录 [英] POSIX named pipe (fifo) drops record in nonblocking mode

查看:54
本文介绍了POSIX 命名管道 (fifo) 在非阻塞模式下删除记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 POSIX 命名管道 (fifos) 从一个或多个线程发送记录以供另一个线程读取(只有一个线程进行读取).但是,100 条记录中的第 83 条记录被简单地删除.客户端核心调用 write 并且返回值正确报告为记录的长度(720 字节),因此客户端(写入器)核心确认记录已发送,但在 gdb 调试模式下切换到读取器核心并使用调度程序锁定上,我循环读取之前的几条记录,然后读取失败——管道中没有记录,即使客户端(写入器)核心确认了写入.

I am using POSIX named pipes (fifos) to send records from one or more threads to be read by another thread (only one thread does the reading). However, the 83rd record out of 100 records is simply dropped. The client core calls write and the return value is correctly reported as the length of the record (720 bytes) so the client (writer) core confirms that the record is sent, but switching to the reader core in gdb debug mode with scheduler-locking on, I cycle through reading the few previous records and then read fails -- no record in the pipe, even though the client (writer) core confirmed the write.

管道容量为 65,536 字节(Linux 中默认).我假设每读取一条记录,管道内容就会减少 1 条记录,因此在删除第 83 条记录时,管道中有大约 5 条先前的记录,即 3600 字节——不足以填满管道.

The pipe capacity is 65,536 bytes (by default in Linux). I assume the pipe contents are reduced by 1 record for each record read, so at the point where the 83rd record is dropped I have about 5 prior records in the pipe, or 3600 bytes -- not enough to fill the pipe.

我以非阻塞模式打开管道,因为当我以阻塞模式打开它们时,两端都冻结了.根据 http://man7.org/linux/的手册页man-pages/man7/fifo.7.html, "FIFO必须在两端(读和写)都打开,数据才能通过.通常,打开FIFO阻塞,直到另一端也打开."我的问题是两端都阻塞了,不会走得更远.它还说,在 Linux 下,打开 FIFO 进行读写将在阻塞和非阻塞模式下成功.POSIX 未定义这种行为."

I opened the pipes in nonblocking mode because when I opened them in blocking mode both ends froze. According to the man pages at http://man7.org/linux/man-pages/man7/fifo.7.html, "The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also." My problem is that both ends block and won't go further. It also says, "Under Linux, opening a FIFO for read and write will succeed both in blocking and nonblocking mode. POSIX leaves this behavior undefined."

每一端的代码很简单:

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; }

C 函数是从我的 NASM 程序中调用的:

The C functions are called from my NASM program:

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

我的问题是:

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

  1. What could cause the dropped record? It does not look like pipe capacity unless the pipe is not emptied with the read of each record -- even all 83 records would take 59760 bytes, below the 65K pipe capacity in Linux. It could be due to nonblocking mode, but if the pipe is not full there would be no reason to block.

我怎样才能在阻塞模式下打开两端(假设两端都冻结了,每个都在等待另一个),我在阻塞模式下有什么问题吗?

How can I open both ends in blocking mode (given that both ends freeze, each waiting for the other), and are there any problems would I have with blocking mode?

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

I could open both ends in read/write mode because my code only writes on from one or more threads on one end and reads from 1 thread (only) on the other end. While "POSIX leaves this behavior undefined" are there any reasons not open both ends in read/write mode in this situation?

我没有发布有关此问题的任何其他代码(除了上述问题),因为我只是在寻找有关在我描述的情况下处理丢失记录问题的最佳方法的想法.

I have not posted any other code with this question (except as above) because I'm only looking for ideas on the best way to handle the problem of a dropped record in the case I described.

推荐答案

您有多个编写器使用一个 FIFO 发送 720 字节的消息.POSIX 只要求写入 PIPE_BUF(通常为 512 字节)是原子的.这意味着较长的写入可能会被其他线程的写入交错并损坏.

You have multiple writers using one FIFO sending messages of 720 bytes. POSIX only requires writes of PIPE_BUF (512 bytes, normally) to be atomic. That means that longer writes can get interleaved by writes from other threads and get corrupted.

无论 PIPE_BUF 大小如何,管道都是流,它们没有消息的概念,这意味着您需要自己分隔消息,而您的代码不会这样做.换句话说,当有多个写入者时,您的阅读器代码不可能恢复单个消息.

Regardless of PIPE_BUF size, pipes are streams and they don't have a notion of a message, and that means you need to delimit messages yourself, which your code doesn't do. In other words, your reader code cannot possibly recover the individual messages when there are multiple writers.

您可能喜欢使用 Unix 数据报套接字反而.进入 Unix 数据报套接字的每条消息都是一条原子消息,它在一个系统调用(sendtorecvfrom)中完全写入和读取.

You may like to use a Unix datagram socket instead. Each message into a Unix datagram socket is an atomic message and it gets written and read completely in one syscall (sendto and recvfrom).

这篇关于POSIX 命名管道 (fifo) 在非阻塞模式下删除记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆