【QT 之 Synchronizing Threads】 同步线程

【QT 之 Synchronizing Threads】 同步线程

虽然线程的目的是允许代码并行运行,但有时线程必须停止并等待其他线程。例如,如果两个线程试图同时写入同一个变量,结果是未定义的。强制线程相互等待的原理称为互斥。这是一种用于保护共享资源(如数据)的通用技术。
Qt提供了用于同步线程的低级原语以及高级机制。

Low-Level Synchronization Primitives(低级同步基元)

QMutex 是一个强制互斥的基础类,线程锁定互斥对象以获得对共享资源的访问权限。如果第二个线程试图在互斥锁已被锁定的情况下锁定它,那么第二个进程将进入睡眠状态,直到第一个线程完成任务并解锁互斥锁。
QReadWriteLock类似于QMutex,只是它区分了“读”和“写”访问。当一段数据没有被写入时,多个线程同时从中读取是安全的。QMutex强制多个读取器轮流读取共享数据,但QReadWriteLock允许同时读取,从而提高了并行性。
QSemaphoreQMutex的推广,它保护一定数量的相同资源。相反,QMutex只保护一个资源。

QWaitCondition不是通过强制互斥而是通过提供条件变量来同步线程。当其他原语使线程等待资源解锁时,QWaitCondition使线程等待,直到满足特定条件。要允许等待的线程继续,请调用wakeOne()来唤醒一个随机选择的线程,或者调用wakeAll()来同时唤醒所有线程。
这些同步类可以用于使方法线程安全。然而,这样做会导致性能损失,这就是为什么大多数Qt方法不能实现线程安全的原因。

Risks

如果线程锁定了资源但没有解锁,则应用程序可能会冻结,因为其他线程将永远无法使用该资源。例如,如果抛出异常并强制当前函数返回而不释放其锁,就会发生这种情况。
另一种类似的情况是死锁。例如,假设线程A正在等待线程B解锁资源。如果线程B也在等待线程A解锁不同的资源,那么两个线程最终都将永远等待,因此应用程序将冻结。

方便的类

QMutexLocker、QReadLocker和QWriteLocker是使QMutex和QReadWriteLock更易于使用的便利类。它们在构建资源时锁定资源,在销毁资源时自动解锁资源。它们旨在简化使用QMutex和QReadWriteLock的代码,从而减少资源意外被永久锁定的可能性。

高级事件队列

Qt的事件系统对于线程间通信非常有用。每个线程都可能有自己的事件循环。要调用另一个线程中的槽(或任何可调用的方法),请将该调用放在目标线程的事件循环中。这允许目标线程在插槽开始运行之前完成其当前任务,而原始线程继续并行运行。
要在事件循环中放置调用,请进行排队的信号槽连接。无论何时发出信号,事件系统都会记录其自变量。然后,信号接收器所在的线程将运行该插槽。或者,调用QMetaObject::invokeMethod()以在没有信号的情况下实现相同的效果。在这两种情况下,都必须使用排队连接,因为直接连接会绕过事件系统并立即在当前线程中运行该方法。
与使用低级原语不同,使用事件系统进行线程同步时没有死锁的风险。但是,事件系统并不强制执行互斥。如果可调用方法访问共享数据,则它们仍然必须使用低级原语进行保护。
话虽如此,Qt的事件系统以及隐式共享的数据结构提供了传统线程锁定的替代方案。如果只使用信号和槽,并且线程之间不共享任何变量,那么多线程程序可以完全不使用低级原语。

下一期 Reentrancy and Thread-Safety 重入和线程安全

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值