bthread源码分析(六)bthread同步机制

Butex是bthread的32位同步原语,用于bthread或pthreads同步。本文分析了Butex数据结构、wait&wakeup模型、生命周期和同步流程,讨论了资源池管理避免的竞态条件和可能的虚假唤醒问题。
摘要由CSDN通过智能技术生成

Butex

butex是bthread使用的类futex的32bit同步原语,可用于bthreads或者pthreads的同步,不可用于同步多进程。

源码地址:bthread/butex.h bthread/butex.cpp

Butex数据结构

如图,每个Butex内部包含一个32bit的用于同步的value和一个WaiterList。bthread进行同步操作时先判断Butex中的value是否和expect value相等,若是那么此bthread拿到了这个Butex,否则在栈上分配一个Waiter,加入WaiterList等待唤醒,并切换上下文到下一个bthread。当唤醒发生,从WaiterList中删除Waiter,并调度该bthread

wait & wakeup模型

butex提供两种基本操作,wait和wake,对外提供的api基于这两种基本操作衍生,例如butex_wake_all,bthread_wake_except等。这里对wait和wake这两个基本操作组成的模型做剖析。

model1

thread1          thread2

wait()             value = new_value

                      wake()

在这种模型中,thread1的wait()在thread2的wake()之前发生,注意wait()和wake()存在memory_order中的sequenced-before关系,而value不参与,只是在使用wake的线程中保证value的设置先于wake()发生,所以又细分了两种情况,即wait()看到了value,或者没看到。

对前者来说,全局顺序是

  • thread2 value = new_value
  • thread1 wait()
  • thread2 wake()

value = new_value先于wait()发生,wait()不会进入睡眠而是直接返回,后续的wake()无效果。

对后者来说,全局顺序是

  • thread1 wait()
  • thread2 value = new value
  • thread2 wake()

这里wait()先于value = new value发生,thread1看到的是old_value进入睡眠,在stage3中被thread2的wake()唤醒

model2

thread1          thread2

                      value = new_value

                      wake()

wait()

这种模型中只有一种情况,wait()看到value的新值,从而直接return

Butex生命周期

Butex的生命周期通过资源池管理,也就是说Butex对象一经从资源池中获取就不会被销毁,这样设计最主要的原因是为了解决butex_wake()和butex_destroy()之间的竞态条件,不妨看下下面这个场景

class Event {

public:

    void wait() {

        mutex_.lock();

        if (!done_)

            cond_.wait();

        mutex_.unlock();

    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Qt 中可以使用信号槽机制来实现线程间的通信。 具体实现步骤如下: 1. 定义一个继承自 QThread 的线程类 BThread,重写其 run() 方法,该方法中可以通过调用 wait() 函数来等待 A 线程发出信号。 ``` class BThread : public QThread { Q_OBJECT public: void run() override { // 等待 A 线程发出信号 wait(); // 执行 B 线程的后续代码 // ... } signals: void startSignal(); }; ``` 2. 在 A 线程中创建一个 BThread 类的实例,然后连接 BThread 实例的 startSignal() 信号和 A 线程的槽函数,当 A 线程发出该信号时,B 线程就可以开始执行后续代码。 ``` class AThread : public QThread { public: void run() override { // 创建 B 线程的实例 BThread bThread; // 连接 startSignal() 信号和槽函数 connect(&bThread, &BThread::startSignal, this, [](){ // 发出信号,通知 B 线程开始执行 emit startSignal(); }); // 启动 B 线程 bThread.start(); // ... } signals: void startSignal(); }; ``` 3. 在 B 线程中等待 A 线程发出信号的函数中,使用 QWaitCondition 类来进行等待,当 A 线程调用 startSignal() 信号时,可以通过调用 QWaitCondition 类的 wakeAll() 函数来唤醒 B 线程继续执行后续代码。 ``` class BThread : public QThread { Q_OBJECT public: void run() override { QMutex mutex; QWaitCondition waitCondition; mutex.lock(); // 等待 A 线程发出信号 waitCondition.wait(&mutex); mutex.unlock(); // 执行 B 线程的后续代码 // ... } signals: void startSignal(); }; ``` 通过以上步骤,就可以在 A 线程启动 B 线程后,通过信号槽机制实现 A 线程给 B 线程发送信号,让 B 线程继续执行后续代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值