[英]Named pipe + SELECT with NONBLOCK mode in Linux
我正在嘗試使用O_NONBLOCK模式創建命名管道,並在單獨的線程中使用“ SELECT”方法偵聽讀取事件。 當我在主線程中經過一些睡眠時間后嘗試關閉程序時出現問題。 我希望當使用close方法關閉命名管道的文件描述符時,select操作應立即停止並返回一些值。 但是不幸的是,當關閉文件描述符並且執行select方法的線程掛起時,select操作沒有任何反應。
有什么想法如何解決嗎? 示例代碼如下。
#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...\r\n");
select(nfd, &rfd, NULL, NULL, NULL);
printf("Close listener...\r\n");
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 immediately\r\n");
close(fd);
printf("Descriptor closed wait for thread to to be closed\r\n");
pthread_join(t, NULL);
printf("Thread is closed - everything is fine\r\n");
}
};
int main()
{
CPipeTest pi;
pi.fnInit();
return 0;
}
盡量避免在一個線程中寫入變量,而在另一個線程中讀取變量。
通過避免,我的意思是不要這樣做。 :)
除非您正在同步訪問fnRunThread
使用的每個變量,否則該函數僅應接觸該函數。
在這里,您要有人做您的工作: 如果在單獨的線程中關閉(2)文件描述符,select(2)會做什么? 並指出了未定義的行為。
解決此問題的一種好方法是使用“停止閱讀”命令,您可以將其傳遞給fifo。 當讀取線程得到它時,它將繼續停止讀取,然后關閉文件。 (請注意,讀取線程關閉了文件句柄-如果讀取線程正在從文件句柄讀取,則表示它擁有該文件句柄。除非進行其他同步,否則在啟動線程后,您應該只讀取或寫入以下變量:由線程中的線程擁有,並且不應在線程外部讀取或寫入這些變量)。
應該有兩個文件描述符,一個用於讀取,另一個用於寫入。
對於阻塞模式, 在啟動“ reader”線程之后 ,應該在初始線程中打開用於寫入的代碼(您將在初始線程中關閉)。 用於讀取的內容應在讀取器線程中打開。 對於非阻塞模式,它可以在同一線程中完成,如果您首先打開進行讀取,然后進行寫入 (或者將返回ENXIO
以打開沒有讀取器的寫入器)。
當您關閉書寫側時,閱讀側將收到帶有select
通知。 (如果進行真正的數據交換,則以下read
將讀取零字節,這就是您檢測EOF的方式)。
如果切換到匿名管道,則會從pipe
調用中自動獲得一對描述符。
這個問題是一個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 immediately\r\n");
close(write_fd); // close the other end
....
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.