线程的互斥和同步(7)- Qt的条件变量QWaitCondition

QWaitCondition 提供了一个用于同步线程的条件变量。它允许一个线程后告诉其他的线程已经满足了某种条件; 一个或多个线程可以阻塞等待 QWaitCondition 来使用 wakeOne() 或 wakeAll() 设置条件。 使用 wakeOne() 唤醒一个随机选择的线程或者 wakeAll() 唤醒全部等待的线程。


下面是 QWaitCondition 类中,常用的函数介绍:

bool wait (QMutex *lockedMutex, unsigned long time = ULONG_MAX)

释放锁资源等待等待条件。lockedMutex 初始化必须是上锁的状态,根据调用的线程。 如果 lockedMutex 没有上锁, 他的行为是未知的。如果 lockedMutex 是可递归的锁,则该函数立即返回。 lockedMutex 将被解锁,调用线程将被阻塞,直到满足以下任一条件:

  • 另一个线程使用 wakeOne()wakeAll() 发出信号。在这种情况下,这个函数将返回true
  • 时间毫秒已经过去。如果时间是ULONG_MAX(默认值),那么等待将永远不会超时(必须通知事件)。如果等待超时,这个函数将返回 false

lockedMutex 将返回到相同 locked 状态。此函数提供了允许原子性的从锁定状态转换到等待状态。。

void wakeOne () 和 void wakeAll ()

表示唤醒一个或多个线程。唤醒的顺序是根据操作系统的调度决定的。


上一篇文章我们介绍了使用信号量实现 生产者-消费者 例子
线程的互斥和同步(6)- Qt的信号量QSemaphore
条件变量是一个针对信号量的可替代选择,本篇文章将使用条件变量替代信号量,实现同样的效果:

数据定义,头文件:

#include <QSemaphore>
#include <QWaitCondition>
#include <QMutex>
#include <atomic>

extern "C" int g_data[20];
extern "C" int g_nStartIndex;
extern "C" int g_nEndIndex;
extern "C" int g_nCurrentCreated;
extern "C" QWaitCondition g_notFullCondition;	// 未满条件变量
extern "C" QWaitCondition g_notEmptyCondition;	// 未空条件变量
extern "C" QMutex g_mutex;

cpp文件

int g_data[20] = {-1};
int g_nStartIndex = 0;
int g_nEndIndex = 0;
int g_nCurrentCreated = 0;
QWaitCondition g_notFullCondition;
QWaitCondition g_notEmptyCondition;
QMutex g_mutex;

生产者实现:

void ProducerThread::run(void)
{
    while (1)
    {
        g_mutex.lock();
        // 当缓存满了的时候,等待是否有消费者消费
        if (g_nCurrentCreated == 20)
            g_notFullCondition.wait(&g_mutex);
        g_mutex.unlock();

        // 生产数据
        g_data[g_nEndIndex] = number;
        std::cout << "Created Data: " << number++ \
                  << ", Index is " << g_nEndIndex << std::endl;

        g_nEndIndex++;
        if (g_nEndIndex == 20)
            g_nEndIndex = 0;

        ::Sleep(100);

        g_mutex.lock();
        g_nCurrentCreated++;
        // 唤醒消费者
        g_notEmptyCondition.wakeAll();
        g_mutex.unlock();
    }
}

消费者实现:

void ConsumerThread::run(void)
{
    while (1)
    {
        g_mutex.lock();
        // 等待
        if (g_nCurrentCreated == 0)
            g_notEmptyCondition.wait(&g_mutex);
        g_mutex.unlock();

        // 消费数据
        std::cout << "Read Value: " << g_data[g_nStartIndex] \
                  << ", Index is " << g_nStartIndex << std::endl;

        g_nStartIndex++;
        if (g_nStartIndex == 20)
            g_nStartIndex = 0;

        ::Sleep(2000);

        // 释放资源
        g_mutex.lock();
        g_nCurrentCreated--;
        // 唤醒生产者生产
        g_notFullCondition.wakeAll();
        g_mutex.unlock();
    }
}

程序运行结果
Created Data: 0, Index is 0
Created Data: 1, Index is 1
Read Value: 0, Index is 0
Created Data: 2, Index is 2
Created Data: 3, Index is 3
Created Data: 4, Index is 4
Created Data: 5, Index is 5
Created Data: 6, Index is 6
Created Data: 7, Index is 7
Created Data: 8, Index is 8
Created Data: 9, Index is 9
Created Data: 10, Index is 10
Created Data: 11, Index is 11
Created Data: 12, Index is 12
Created Data: 13, Index is 13
Created Data: 14, Index is 14
Created Data: 15, Index is 15
Created Data: 16, Index is 16
Created Data: 17, Index is 17
Created Data: 18, Index is 18
Created Data: 19, Index is 19
Read Value: 1, Index is 1
Created Data: 20, Index is 0
Read Value: 2, Index is 2
Created Data: 21, Index is 1
Read Value: 3, Index is 3
Created Data: 22, Index is 2
Read Value: 4, Index is 4
Created Data: 23, Index is 3

不会飞的纸飞机
扫一扫二维码,了解我的更多动态。

下一篇文章:线程的互斥和同步(8)- C++11中的互斥锁和条件变量