0

我在我的 C++ 类中使用函数poll()(我认为它可能是 POSIX 的一部分?)C 函数,以便在文件更改时获取事件。这似乎工作得很好 - 但现在我也希望能够在我需要关闭线程时立即退出函数。

我对此进行了研究,并提出了一些我尝试过的想法——比如尝试发送信号,但我不知道如何让它发挥作用。

在下面的代码中(不是 100% 完整,但应该足以说明问题),我有一个 C++ 类,它从构造函数启动一个线程并希望在析构函数中清理该线程。线程调用poll()当文件更改时返回,然后通知委托对象。监视线程循环直到FileMonitor对象指示它可以退出(使用返回布尔值的方法)。

在析构函数中,我想做的是翻转 bool,然后做一些导致poll()立即退出的事情,然后调用 *pthread_join()*。那么,关于如何让poll()立即退出的任何想法?

此代码针对 Linux(特别是 debian),但我也在 Mac 上处理它。理想情况下,poll() API 应该基本相同。

void * manage_fm(void *arg)
{
    FileMonitor * theFileMonitor = (FileMonitor*)arg;
    FileMonitorDelegate * delegate;

    unsigned char c;
    int fd = open(theFileMonitor->filepath2monitor(), O_RDWR);

    int count;

    ioctl(fd, FIONREAD, &count);
    for (int i=0;i<count;++i) {
       read(fd, &c, 1);
    }

    struct pollfd poller;
    poller.fd = fd;
    poller.events = POLLPRI;


    while (theFileMonitor->continue_managing_thread()) {
        delegate = theFileMonitor->delegate;
        if (poll(&poller, 1, -1) > 0) {
            (void) read(fd, &c, 1);
            if (delegate) {
                delegate->fileChanged();
            }
        }
    }
}

FileMonitor::FileMonitor( )
{
    pthread_mutex_init(&mon_mutex, NULL);

    manage_thread = true;

    pthread_mutex_lock (&mon_mutex);

    pthread_create(&thread_id, NULL, manage_fm, this);

    pthread_mutex_unlock(&pin_mutex);

}

FileMonitor::~FileMonitor()
{
    manage_thread = false;

    // I would like to do something here to force the "poll" function to return immediately.

    pthread_join(thread_id, NULL);
}

bool FileMonitor::continue_managing_thread()
{
    return manage_thread;
}

const char * FileMonitor::filepath2monitor()
{
    return "/some/example/file";
}
4

2 回答 2

3

将管道添加到文件监视器类并切换轮询以获取原始文件描述符和管道的读取描述符以进行轮询。当您想唤醒文件监视器类以检查退出时,请通过管道的写描述符发送一个字节,这将唤醒您的线程。

如果您有大量此类文件监视器,则可能会达到进程的最大文件描述符数(有关详细信息,请参阅检查 Linux 中给定进程的打开 FD 限制,在我的系统上它是 1024 软,4096难的)。如果您不介意它们都立即唤醒以检查其退出指示器,则可以让多个监视器类共享一个管道。

于 2014-09-05T19:21:15.330 回答
-2

您应该在 -ing 循环内部(以及之前)使用 pthread条件变量poll,并让另一个线程调用pthread_cond_signal

您可能会考虑使用管道(7)进行自我欺骗(例如,让一个线程写入(2)一个字节- 可能就在pthread_cond_signal之前- 到管道轮询(2) -由另一个线程读取(2)相同的管道) . 另请参阅signal-safety(7)从 Unix 信号处理程序调用 Qt 函数。两者都可以启发你。

使用管道到自我的技巧,假设您poll阅读该管道,poll则将返回。当然,其他一些线程之前会write同一个管道上完成。

另请参阅Philippe Chaintreuil 的回答,他提出了类似的想法。

于 2014-03-03T06:21:42.013 回答