Linux中带有NONBLOCK模式的命名管道+ SELECT
Named pipe + SELECT with NONBLOCK mode in Linux
我试图用O_NONBLOCK模式创建命名管道,并在单独的线程中使用"SELECT"方法侦听读取事件。有一个问题,当我试图在主线程一些睡眠时间后关闭程序。我期望当使用close方法关闭命名管道的文件描述符时,选择操作应该立即停止并返回一些值。但不幸的是,当文件描述符关闭时,选择操作没有反应,执行选择方法的线程只是挂起…
有办法解决吗?示例代码如下:
#include <pthread.h>
#include <limits.h>
#include <cctype>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <exception>
#define BUFFER PIPE_BUF
#define LPVOID void *
#define BOOL int
#define TRUE 1
#define CONST const
#define CHAR char
class CPipeTest
{
public:
int fd;
int nfd;
fd_set rfd;
pthread_t t;
CPipeTest() {};
~CPipeTest() {};
static LPVOID fnExecuteThread(LPVOID lpParam)
{
((CPipeTest*)lpParam)->fnRunThread();
return NULL;
}
BOOL fnRunThread()
{
printf("Going to listen...rn");
select(nfd, &rfd, NULL, NULL, NULL);
printf("Close listener...rn");
return TRUE;
}
void fnInit()
{
CONST CHAR * name = "./test_fifo1";
mkfifo(name, 0777);
fd = open(name, O_NONBLOCK | O_RDONLY);
nfd = fd + 1;
FD_ZERO(&rfd);
FD_SET(fd, &rfd);
pthread_create( &t, NULL, fnExecuteThread, (LPVOID)this);
sleep(30);
printf("Close file descriptor - listener should be closed automatically and immediatelyrn");
close(fd);
printf("Descriptor closed wait for thread to to be closedrn");
pthread_join(t, NULL);
printf("Thread is closed - everything is finern");
}
};
int main()
{
CPipeTest pi;
pi.fnInit();
return 0;
}
应该有两个文件描述符,一个用于读取,另一个用于写入。
对于阻塞模式,写线程(在初始线程中关闭)应该在初始线程中打开,在启动"reader"线程之后打开。reader线程中打开读取的。对于非阻塞模式,可以在同一个线程中完成,如果首先打开读取,然后写入(或者ENXIO
将返回打开没有读取器的writer)。
当您关闭写侧时,读侧将收到select
通知。(如果有一个真正的数据交换,下面的read
将读取零字节,这就是你如何检测EOF)。
如果您切换到匿名管道,您将自动从pipe
调用获得一对描述符。
尽量避免在一个线程中写入一个变量,而在另一个线程中读取它。
我说的避免是指不要那样做。:)
fnRunThread
使用的每个变量只能被该函数访问,除非同步访问它。
这里有人在做你做过的事:如果在一个单独的线程中关闭(2)一个文件描述符,select(2)会做什么?并指出了未定义行为。
解决这个问题的一个好方法是有一个"停止阅读"命令,你可以通过你的fifo。当读取线程获得它时,它继续停止读取,然后关闭文件。(注意,读线程关闭文件句柄——如果读线程正在从文件句柄中读取,那就意味着它拥有文件句柄。除非有一些额外的同步,一旦启动线程,您应该只读取或写入线程内线程拥有的变量,而不应该读取或写入线程外的这些变量)。
问题是FIFO(一种特殊类型的文件)必须在两个结束时打开,然后才能用它做任何事情。这是没有意义的,你关闭相同的一端,并期望其他线程作出反应。
下面的代码应该做你想做的:
....
nfd = fd + 1;
FD_ZERO(&rfd);
FD_SET(fd, &rfd);
int write_fd = open(name, O_WRONLY); // open the other end
pthread_create( &t, NULL, fnExecuteThread, (LPVOID)this);
sleep(30);
printf("Close file descriptor - listener should be closed automatically and immediatelyrn");
close(write_fd); // close the other end
....
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- IPC使用多个管道和分支进程来运行Python程序
- 如何创建函数管道,以便函数一个接一个地运行?
- Gstreamer 管道从命令 lne 到 c 代码
- 外壳包装器句柄/执行交互式命令管道C++ UNIX
- 将旧管道转换为现代 openGL 时出现问题
- SQLite3 在 c++ 中输出 SELECT 上的空列表
- 如何使用管道在父级和子级之间来回传递文件
- 在没有管理员权限的情况下连接到同一网络中的命名管道
- 如何测量管道延迟?
- 我如何使用此程序管道多个命令?C++
- 先进先出:一个进程永远不会从管道读取
- Node.js fs.open() 在尝试打开 4 个以上的命名管道 (FIFO) 后挂起
- 如何在 sys/select.h 中正确使用
- 使用模板而不是虚拟方法的管道模式
- 我可以写入关闭的套接字并强制纠正损坏的管道错误吗?
- 在 Azure DevOps 构建管道中使用英特尔C++编译器为 Linux 环境构建C++代码
- 使用 Select 多路复用未命名的管道和其他文件描述符
- read() 在 select() 阻塞之后,当从生成的进程从管道读取时
- Linux中带有NONBLOCK模式的命名管道+ SELECT