使用bthread并发编程
cpp
#include <gflags/gflags.h>
#include <butil/logging.h>
#include <bthread/bthread.h>
static void* func(void* args) {
std::string* num = static_cast<std::string*>(args);
for(int i = 0; i < 5; i++) {
LOG(INFO) << *num;
bthread_usleep(1000);
}
return NULL;
}
int main() {
bthread_t th1, th2;
std::string a = "bthread:A", b = "bthread:B", c = "bthread:C";
if (bthread_start_background(&th1, NULL, func, static_cast<void*>(&a)) != 0) {
LOG(ERROR) << "Fail to create bthread for part1";
}
if (bthread_start_background(&th2, NULL, func, static_cast<void*>(&b)) != 0) {
LOG(ERROR) << "Fail to create bthread for part2";
}
func(static_cast<void*>(&c));
bthread_join(th1, NULL);
bthread_join(th2, NULL);
}
thread 栈切换事例
cpp
#include <bthread/context.h>
#include <iostream>
::bthread_fcontext_t fc1;
::bthread_fcontext_t fc2;
::bthread_fcontext_t fc_tmp;
intptr_t g_num1 = 0;
intptr_t g_num2 = 0;
static void jumper1(intptr_t param) {
for(int i = 0; i < 9; i++) {
printf("context1: g_num1 = %ld, then jump to context2\n", ++g_num1);
::bthread_jump_fcontext(&fc1, fc2, 0);
}
// 最后结尾,jump到原始上下文中,继续执行
printf("context1: g_num1 = %ld, finally, jump to main\n", ++g_num1);
::bthread_jump_fcontext(&fc1, fc_tmp, 0);
}
static void jumper2(intptr_t param) {
for(int i = 0; i < 10; i++) {
printf("context2: g_num2 = %ld, then jump to context1\n", ++g_num2);
::bthread_jump_fcontext(&fc2, fc1, 0);
}
}
int main() {
static const std::size_t stack_size = 8192;
// 创建两个上下文
void *sp1 = ::malloc(stack_size);
fc1 = ::bthread_make_fcontext((char*)sp1 + stack_size, stack_size, jumper1);
void *sp2 = ::malloc(stack_size);
fc2 = ::bthread_make_fcontext((char*)sp2 + stack_size, stack_size, jumper2);
// 将当前上下文保存到fc_tmp,并切换上下为fc2
::bthread_jump_fcontext(&fc_tmp, fc2, 0);
printf("done\n");
::free(sp1);
::free(sp2);
return 0;
}
ExecutionQueue 的使用
ExecutionQueue是一个mpsc队列,即线程安全的多生产者单消费者队列
cpp
#include <bthread/execution_queue.h>
#include <bthread/bthread.h>
class DemoTask {
public:
void run(int);
};
void DemoTask::run(int count) {
LOG(INFO) << "DemoTask::run(" << count << ")";
}
int comsume(void *meta, bthread::TaskIterator<DemoTask*> &iter) {
if(iter.is_queue_stopped()) {
return 0;
}
int count = 0;
for(; iter; ++iter) {
DemoTask *task = *iter;
task->run(++count);
}
return 0;
}
int main() {
bthread::ExecutionQueueId<DemoTask*> exe_queue;
int ret = bthread::execution_queue_start(&exe_queue, nullptr, comsume, nullptr);
DemoTask *task = new DemoTask();
ret = bthread::execution_queue_execute(exe_queue, task);
bthread_usleep(10);
}