bthread源码分析(九)进阶数据结构 ExecutionQueue

本文详细分析了bthread的ExecutionQueue,这是一个多生产者-单消费者工作队列,特点是wait-free同步,无边界队列大小,自动启动和销毁消费者线程。队列提供有序性和优先级管理,并确保高优先级任务在低优先级任务完成后执行。文章探讨了wait-free实现机制,以及ExecutionQueue的生命周期管理,包括版本号和引用计数在资源池中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ExecutionQueue是一个多生产者-单消费者模型的工作队列,特性:

  • wait-free,基于butex同步
  • 队列元素数量无边界
  • 没有daemon thread存在,消费者线程自动启动、自动销毁。当有任务加入队列,启动一个bthread持续消费队列并执行任务,直到队列为空,销毁这个bthread
  • 提供有序性和优先级管理,高优先级任务先于低优先级任务执行,相同优先级内部任务按照FIFO顺序执行。高优先级任务不是即时抢占的,即若当前正在执行低优先级任务,那么高优先级任务插入不会抢占低优先级任务立刻执行,而且会等待这个低优先级任务执行完成后再启动,即高优先级任务最多延迟一个任务调度
  • 用户类型T必须支持拷贝构造

源码位置 bthread/execution_queue.h bthread/execution_queue_inl.h bthread/execution_queue.cpp

wait-free实现

ExecutionQueue中每个任务包装在一个TaskNode中,ExecutionQueue中维护一个单链表表头,所有任务通过next指针连接在这个链表中。每次新增任务从head加入,只有头节点有执行任务的权利,头节点添加者启动一个bthread遍历所有TaskNode链表直到所有任务执行完毕,如图:

执行过程后不断有新任务加入,如图:

之前有4个任务,任务1是头节点,将链表反序后顺序执行,本次执行完1,2,3,4任务,此时有新增任务5,6加入,继续执行,直到没有新加入节点为止

业务调用start_execute执行一个任务,伪代码如下:

start_execute(TaskNode *node) {

    node->next = UNCONNECTED             // 设置为一个非0的非法值

    prev_head = _head.exchange(node)    // exchange是wait-free的

    if (prev_head != nullptr) {         // 之前的头节点非空,更新next并直接返回

        node->next = prev_head

        return

    }

    // 到这里获取执行权,启动一个bthread遍历nodes,对每个节点执行用户函数

    start a bthread to execute user func

}

通过exchange保证了wait-fre

<think>好的,用户想了解如何在C++中使用bthread进行并发编程。首先,我需要回忆一下bthread的基本概念。bthread是百度开源的BRPC框架中的用户态线程库,类似于协程,用于高并发场景。用户可能已经知道多线程,但想用更轻量级的并发方式。 接下来,我需要说明使用bthread的基本步骤。首先,应该包括必要的头文件,比如<bthread/bthread.h>。然后,编写任务函数,这个函数的签名需要符合void* (*)(void*)的形式。然后,使用bthread_start_background或bthread_start_urgent来启动bthread。这些函数类似于pthread_create,但管理的是用户态线程。 然后,可能需要提到如何编译和链接程序,需要链接brpc库,使用-lbrpc。另外,bthread的启动函数参数可能需要传递数据,可以通过结构体封装数据,并在任务函数中释放,避免内存泄漏。 还要注意bthread的同步机制,比如bthread的join,或者使用互斥锁和条件变量。例如,bthread_join可以等待bthread结束。同时,bthread的同步原语可能与pthread的不同,需要特别说明。 可能还需要提到bthread和普通线程的区别,比如bthread由调度器管理,可以在多个pthread之间调度,减少上下文切换开销。此外,bthread的栈大小可以调整,适合高并发。 用户可能需要一个示例代码来展示如何启动bthread,传递参数,以及等待其完成。在示例中,结构体的使用和资源的释放是关键点,避免内存泄漏。例如,定义一个结构体包含需要传递的参数,在任务函数中转换为该结构体,处理完后delete。 还需要注意错误处理,检查bthread_start_background的返回值,确保bthread创建成功。另外,bthread的函数可能返回错误码,需要进行适当的处理。 最后,要总结使用bthread的优势,比如高并发、低开销,以及注意事项,如避免阻塞操作,合理管理资源。然后根据这些内容,提出相关问题,帮助用户进一步理解bthread与其他并发机制的区别、同步方法、与pthread的对比,以及适用场景。</think><< 在BRPC框架中使用bthread进行并发编程时,主要通过以下步骤实现: 1. 包含必要头文件: ```cpp #include <bthread/bthread.h> #include <butil/logging.h> ``` 2. 编写任务函数: ```cpp void* task_func(void* arg) { int* value = static_cast<int*>(arg); LOG(INFO) << "bthread processing value: " << *value; delete value; // 清理动态分配的内存 return nullptr; } ``` 3. 启动bthread: ```cpp int main() { for (int i = 0; i < 5; ++i) { int* arg = new int(i); // 动态分配参数内存 bthread_t tid; if (bthread_start_background(&tid, nullptr, task_func, arg) != 0) { LOG(ERROR) << "Failed to create bthread"; delete arg; } } // 等待所有bthread完成(示例) while (bthread_getconcurrency() > 1) { usleep(10000); } return 0; } ``` 实现原理和注意事项: 1. 用户态线程:bthread是M:N线程模型,由BRPC的调度器管理,比操作系统线程更轻量 2. 非抢占式调度:bthread主动让出CPU时才会切换,通常通过bthread_usleep等阻塞操作触发 3. 栈管理:每个bthread有独立栈空间(默认1MB),可通过brpc::Controller调整 4. 资源管理:参数需要动态分配并在任务中释放,避免悬垂指针 5. 同步机制:使用bthread::Mutex、bthread::ConditionVariable等配套同步原语 编译命令示例: ```bash g++ -std=c++11 example.cpp -lbrpc -lpthread ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值