生产者和消费者无限期地等待应用程序何时退出

Producers and consumers waiting indefinitely when the application should exit

本文关键字:应用程序 何时 退出 等待 消费者 无限期 生产者      更新时间:2023-10-16

我实现了一个线程安全的阻塞队列,使用QMutex对象,QWaitCondition对象用于生产者线程,QWaitCondition对象用于消费者线程。函数enqueue()dequeue()如下图所示:

void MyQueue::enqueue(const QString& s)
{
    _mutex.lock();
    while (_queue.size() == _maxSize) { _producer.wait(&_mutex); }
    _queue.enqueue(s);
    _consumer.wakeAll();
    _mutex.unlock();
}
QString MyQueue::dequeue()
{
    QString s;
    _mutex.lock();
    while (_queue.empty()) { _consumer.wait(&_mutex); }
    s = _queue.dequeue();
    _producer.wakeAll();
    _mutex.unlock();
    return s;
}

需要访问这个共享队列的消费者线程和生产者线程有一个构造函数,该构造函数接受一个MyQueue对象的引用。上面的实现可以正常工作,但是当主程序必须终止时就会出现问题,因为一些消费者或生产者无限期地等待,特别是:

  1. 如果队列是空的,并且一个消费者已经调用了dequeue()函数,这个消费者将无限期等待。
  2. 如果队列已满,并且某个生产者调用了enqueue()函数,则该生产者将无限期等待。

我怎样才能解决这个问题?

我认为处理终止的最简单的方法可以是使用原子标志(您可以使用std::atomic_bool或QAtomicInt)并让_consumer.wait使用超时。

当您检测到超时时(如果发生超时,wait返回false),如果cancel==true则检查标志,然后退出,否则再次等待。因此在最坏的情况下,它们将等待time毫秒,然后退出。

如果终止是唯一的问题,您可以通过在while循环中添加另一个检查条件来解决这个问题:

    while (_queue.size() == _maxSize) {
        _producer.wait(&_mutex);
        if (_queue.shutting_down()) return;
    }

这个队列可以通过一个API来增强,该API将设置关闭标志,然后唤醒任何可能仍在等待它的线程。

想到的最简单的方法是提供一个全局布尔值(exit_now或其他东西),您将其设置为true,然后广播到两个条件变量以唤醒。它们醒来,检查布尔值,然后退出线程。