如何以最优方式访问线程专属索引?
线程专属队列访问的索引优化方案
我在程序中创建了n个线程,所有线程都从同一个主线程函数启动,创建线程时会给这个函数分配唯一的thread_index:
void worker_main_func(int thread_index); vector<thread> spawn_workers(int n) { vector<thread> workers; workers.reserve(n); for (int i = 0; i < n; ++i) workers.emplace_back(worker_main_func, i); } return workers; }
每个工作线程需要访问一个预先分配好的专属队列,线程要通过thread_index来定位自己的队列:
static vector<my_queue_t> g_queues; void do_some_work(); void worker_main_func(int thread_index) { do_some_work(); }
void do_some_work() { // ... g_queues[get_this_thread_index_somehow()].some_operation_on_queue(); // ... }
我没办法把thread_index直接传递给do_some_work,因为这要修改几乎整个代码库——每个相关函数都得加这个参数。更关键的是,当前有些函数的参数是通过寄存器传递的,加参数后可能得改成栈传递,会带来性能损耗:
void do_some_work(int thread_index); void calculate(int thread_index, /* params */); void fetch_data(int thread_index, /* params */); void implementation1(int thread_index, /* params */); void blablabla(int thread_index, /* params */);
所以我改用thread_local变量存储thread_index,需要时直接读取:
thread_local int g_thread_index; void worker_main_func(int thread_index) { g_thread_index = thread_index; do_some_work(); }
void do_some_work() { // ... g_queues[g_thread_index].some_operation_on_queue(); // ... }
这种方法能正常工作,但不是最优解。编译器每次读取g_thread_index时都会从内存(或缓存)取值,有时还会额外添加初始化保护逻辑。
但实际上,线程的所有工作都在worker_main_func的调用链里,也就是说worker_main_func及其参数始终在栈底:
--- inner_most_call ---- ... param2 param1 --- fetch_data --------- param3 param2 param1 --- calculate1 --------- --- do_some_work ------- thread_index --- worker_main_func ---
理论上编译器完全不用从内存读g_thread_index,只要从当前线程栈的固定偏移位置读取就行。
我也考虑过用std::this_thread::get_id()替代自定义的thread_index,但这会触发pthread_self调用,还得把不透明的thread::id映射到[0..n)范围的索引,反而更麻烦。
内容的提问来源于stack exchange,提问作者janekb04
相关产品推荐
相关产品推荐

