【问题标题】:Is Qt's QBuffer thread safe?Qt 的 QBuffer 线程安全吗?
【发布时间】:2012-12-13 17:28:55
【问题描述】:

我在ReadWrite 模式下使用QBuffer。一名工作人员 QThread 将数据推送到缓冲区中,另一名工作人员 QThread 从中读取数据。

QBuffer 是否保证线程安全,还是我需要从 QBuffer 派生并添加互斥体?

【问题讨论】:

  • 您只有一个 pos(),因此您需要在单个临界区中进行 seek() 和 read() 或 write()。此外,如果缓冲区为空/满,read()/write() 可能应该阻塞?这与 QBuffer/QIODevice 语义完全不同,值得拥有自己的类。
  • QBuffer 不是管道。它根本不适合您使用,线程与否!你使用它的方式最终会耗尽内存,因为缓冲区只能增长,不能缩小。如果你想要一个呈现两个 QIODevice 的类,比如管道的末端,你需要创建你自己的。您也可以重复使用QRingBuffer (#include <private/qringbuffer_p.h>),但必须对它的访问进行互斥保护。
  • 真正要查找的内容称为lock-free queue - 查看最受好评的答案,它有很好的参考资料。

标签: c++ qt thread-safety


【解决方案1】:

引用马克·萨默菲尔德的书C++ GUI Programming with Qt 4:

Qt 的线程安全类包括 QMutex、QMutexLocker、QReadWriteLock、 QReadLocker、QWriteLocker、QSemaphore、QThreadStorage 和 QWaitCondition。此外,部分 QThread API 和几个 其他函数是线程安全的,特别是 QObject::connect(), QObject::disconnect()、QCoreApplication::postEvent() 和 QCoreApplication::removePostedEvents()。

Qt 期望您在它的大多数类周围使用锁定机制。如果是,文档会说“所有函数都是线程安全的”,并且各个函数也会指定“是线程安全的”。

Notes on Qt Classes

许多 Qt 类是可重入的,但它们不是 使它们成为线程安全的,因为使它们成为线程安全的会导致 重复锁定和解锁 QMutex 的额外开销。为了 例如,QString 是可重入的,但不是线程安全的。你可以放心 从多个线程访问不同的 QString 实例 同时,但你不能安全地访问同一个实例 同时来自多个线程的 QString(除非你保护 使用 QMutex 访问自己)。

一些 Qt 类和函数是 线程安全的。这些主要是线程相关的类(例如 QMutex) 和基本函数(例如 QCoreApplication::postEvent())。

因为QBufferQIODevice 的直接子类,我特别希望它不是线程安全的,但是有些容器类对于读访问是线程安全的,但需要锁定以进行写访问:

Container Classes

容器类是隐式共享的,它们是可重入的,并且 它们针对速度、低内存消耗和最小化进行了优化 内联代码扩展,导致更小的可执行文件。此外, 它们在用作只读的情况下是线程安全的 用于访问它们的所有线程的容器。

【讨论】:

    【解决方案2】:

    QBuffer 不是线程之间通信的最佳方式,因为写入它会使缓冲区增长,但从它读取并不会从一开始就删除数据。

    您可以改为使用带有QByteArray 参数的信号/插槽,使用QLocalSocket 或自己编写从QIODevice 派生的线程安全环形缓冲区类。

    【讨论】:

    • 非常好。是的,我最终从QIODevice 派生了我的自定义内存管理和线程安全锁。此外,对于那些可能有兴趣走这条路线并且像我一样如果您需要优先考虑读取优先于写入或其他方式的人,请考虑在实现线程安全时使用QReadWriteLock 而不是QMutex
    【解决方案3】:

    这扩展了 QIODevice,并且那里的文档指出 QIODevice 上的所有方法都是可重入的,但在此之上没有指定任何线程安全性。鉴于 QBuffer 没有提及更多内容,我希望 QBuffer 不是线程安全的。

    http://qt-project.org/doc/qt-4.8/qiodevice.html

    【讨论】:

      【解决方案4】:

      Qt 中线程之间最简单的通信方式是将事件发布到另一个线程的事件队列中。这假设另一个线程旋转一个事件循环。它只需要定期在您通常检查新数据等的地方旋转它。

      【讨论】:

      • 先生,您怎么敢给那些寻求老练的人提供如此简单的建议?肯定投反对票!
      【解决方案5】:

      正如其他几位发帖人所指出的,QBuffer 是不适合这项工作的工具,无论线程安全问题如何。

      Is there an intra-process local pipe in Qt? 描述了一个基于 QIODevice 的 FIFO 队列,它更适合预期目的(尽管它不包含任何线程安全机制)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-15
        • 2018-07-18
        • 1970-01-01
        • 2011-07-04
        • 2014-04-26
        • 2012-11-30
        • 2010-12-30
        • 2013-03-12
        相关资源
        最近更新 更多