1

我正在尝试使用 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...\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;

}
4

3 回答 3

0

应该有两个文件描述符,一个用于读取,另一个用于写入。

对于阻塞模式,在启动“阅读器”线程后,应在初始线程中打开用于写入的模式(您将在初始线程中关闭) 。用于阅读的应在阅读器线程中打开。对于非阻塞模式,它可能在同一个线程中完成,如果你先打开读取,然后写入(或ENXIO将返回打开没有读取器的写入器)。

当您关闭写入端时,读取端将收到通知select。(如果有真正的数据交换,以下read将读取零字节,这就是您检测 EOF 的方式)。

pipe如果您切换到匿名管道,您将自动从调用中获得一对描述符。

于 2013-01-14T21:58:49.887 回答
0

尽量避免在一个线程中写入变量,并在另一个线程中读取它。

避免,我的意思是不要那样做。:)

除非您正在同步访问它,否则使用的每个变量都fnRunThread应该只被该函数触及。

在这里,您有人在做您所做的事情: 如果您在单独的线程中关闭(2)文件描述符,那么 select(2) 会做什么? 并指出未定义的行为。

解决这个问题的一个好方法是有一个“停止阅读”命令,你可以通过你的 fifo。当读取线程得到它时,它会继续停止读取,然后关闭文件。(请注意,读取线程会关闭文件句柄——如果读取线程正在从文件句柄中读取,则意味着它拥有它。除非进行一些额外的同步,一旦你启动线程,你应该只读取或写入变量由线程中的线程拥有,不应在线程外读取或写入这些变量)。

于 2013-01-14T21:55:06.997 回答
0

问题是 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
    ....
于 2013-01-14T22:51:50.143 回答