为什么我不必在使用qt等待条件时包装锁定/解锁语句?

时间:2013-11-22 12:27:11

标签: c++ multithreading qt

我非常清楚做多线程,尽管头痛得厉害,但我仍然觉得它令人难以置信。我正在使用qt并且一直在检查教程并找到一个完全适用于我的情况,即将数据流式传输到循环缓冲区,一个线程写入其中,一个线程读出它。这是教程here。首先让我问你是否在等待条件下选择了正确的方法。

我选择不使用信号量,因为缓冲区的大小可能随时从主线程改变,导致重新分配和重新调整读/写索引,并且调整信号量的大小并不容易。我不想在循环中放置if比较是否执行循环体,因为它必须一遍又一遍地做,直到它可以在缓冲区中容纳更多数据,所以等待条件是我的自然解决方案

其次,我对他们的例子中等待条件的作用感到有些困惑。它们似乎锁定互斥锁,检查等待条件和阻塞,在满足条件时继续,然后在那里解锁互斥锁。这是否意味着对写入缓冲区的访问在那时完全不受保护?

第三,当我的主线程要停止时,我对如何结束这些线程感到有点失落。我不能使用等待条件,因为我希望它们只要主线程愿意运行,我不认为我可以通过线程发出信号告诉它退出。是通知线程停止执行的唯一方法,在每个循环中放置一个if不断检查位于主线程中的bool,然后等待线程在析构函数中退出?问题是,在等待条件下,我必须首先设置bool退出,然后唤醒两个线程。我真的很困惑在这里做什么,任何建议都表示赞赏。

2 个答案:

答案 0 :(得分:1)

首先,是的,等待条件是这项工作的正确工具。

他们使用等待条件并不是最好的,因为有时线程会过早被唤醒。他们的if语句应该是一个while循环,例如

while (numUsedBytes == 0)
    bufferNotEmpty.wait(&mutex);

其次,仔细编写生产者和消费者,以便生产者拥有缓冲区中的一些字节,而消费者拥有其他字节。也就是说,消费者拥有未经检查数据的部分,而产品拥有未使用的部分。这就是为什么他们可以安全地在缓冲区中读取或写入一个字节,因为它们可以保证其他线程不使用该字节。

第三,结束这样的线程很困难,但你的想法大多是正确的。如果主程序知道何时结束,则将等待循环更改为:

while (numUsedBytes == 0)
    bufferNotEmpty.wait(&mutex);
    if (TimeToEnd) {unlock(); return;}

主要是,到了结束的时候你说

lock();
TimeToEnd = true;
wakeAll();
unlock();
joinAllThreads();

如果生产者知道什么时候结束,那么就会发生类似的事情,主程序在创建所有线程后立即加入所有线程。

答案 1 :(得分:1)

缓冲区访问受到如何选择数据索引的保护:

  1. 消费者看不到缓冲区中的数据,因此阻止
  2. 生产者看到缓冲区未满,因此在索引0的缓冲区中写入一些数据 并唤醒消费者并增加索引t写入索引1
  3. 消费者看到数据并读取索引0
  4. 特别是来自消费者的i % buffersize与关键部分之间的生产者的i % buffersize相同的唯一方式是numUsedBytes == 0并且您是生产者或{{1}你是消费者

    看到这一点你应该能够说明生产者和消费者都不能同时读取或写入同一个索引:ergo访问受到保护

    solution is well researched

    但是这个实现有几个问题:如果条件因任何原因被唤醒,if检查是不够的。他们应该使用QMutexLocker所以例外或提前退货不会搞砸一切:

    numUsedBytes == buffersize