POSIX命名的管道(fifo)在非阻塞模式下丢弃记录。

问题描述 投票:1回答:1

我使用POSIX命名的管道(fifos)从一个或多个线程发送记录给另一个线程读取(只有一个线程进行读取)。 但是,100条记录中的第83条记录被直接丢弃。 客户端核心调用write,返回值正确地报出了记录的长度(720字节),所以客户端(writer)核心确认了记录的发送,但是在gdb调试模式下切换到阅读器核心,并开启了调度器锁定,我循环读取前面几条记录,然后读取失败--管道中没有记录,尽管客户端(writer)核心确认了写入。

管道的容量是65,536字节(Linux默认情况下)。 我假设每读一条记录,管道的内容就会减少1条记录,所以在第83条记录被丢弃的时候,我在管道中大约有5条之前的记录,也就是3600字节--不足以填满管道。

我是在非阻塞模式下打开管道的,因为当我在阻塞模式下打开管道时,两端都冻结了。 根据man pages at http:/man7.orglinuxman-pagesman7fifo.7.html。,"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

我的问题是:

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

  2. 我如何在阻塞模式下打开两端(考虑到两端都冻结,各自等待另一个),阻塞模式会有什么问题吗?

  3. 我可以用读写模式打开两端,因为我的代码只在一端从一个或多个线程写上,而在另一端从1个线程(只)读上。 虽然 "POSIX没有定义这种行为",但在这种情况下,有什么理由不以读写模式打开两端吗?

我没有带着这个问题发布任何其他的代码(除了如上所述),因为我只是在寻找在我描述的情况下处理掉落记录问题的最佳方法。

c linux posix named-pipes
1个回答
3
投票

你有多个写手使用一个fifo发送720字节的消息。POSIX只要求写入的 PIPE_BUF (通常为512字节)是原子的。这意味着,较长的写入可能会被其他线程的写入交错而被破坏。

无论 PIPE_BUF 大小,管道是流,它们没有消息的概念,这意味着你需要自己对消息进行划分,而你的代码并没有做到这一点。换句话说,当有多个写入者时,你的阅读器代码不可能恢复各个消息。

你可能喜欢使用一个 Unix数据报插口 代替。每个进入Unix数据报套接字的消息都是一个原子消息,它在一次系统调用中被完整地写入和读取 (sendtorecvfrom).

© www.soinside.com 2019 - 2024. All rights reserved.