簡體   English   中英

在Linux中使用NONBLOCK模式命名管道+ SELECT

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM