C++ 无锁有界堆栈C++;11原子
我在考虑使用非常基本的有界(预分配)堆栈,以正确的后进先出顺序跟踪线程ID。所以我想知道我的实现是否是线程安全的:C++ 无锁有界堆栈C++;11原子,c++,multithreading,c++11,stack,lock-free,C++,Multithreading,C++11,Stack,Lock Free,我在考虑使用非常基本的有界(预分配)堆栈,以正确的后进先出顺序跟踪线程ID。所以我想知道我的实现是否是线程安全的: // we use maximum 8 workers size_t idle_ids_stack[8]; // position current write happening at std::atomic_uint_fast8_t idle_pos(0); // this function is called by each thread when it is about t
// we use maximum 8 workers
size_t idle_ids_stack[8];
// position current write happening at
std::atomic_uint_fast8_t idle_pos(0);
// this function is called by each thread when it is about to sleep
void register_idle(size_t thread_id)
{
std::atomic_thread_fence(std::memory_order_release);
idle_ids_stack[idle_pos.fetch_add(1, std::memory_order_relaxed)] = thread_id;
}
// this function can be called from anywhere at anytime
void wakeup_one()
{
uint_fast8_t old_pos(idle_pos.load(std::memory_order_relaxed));
std::atomic_thread_fence(std::memory_order_acquire);
size_t id;
do
{
if(old_pos == 0) return; // no idle threads in stack; exit;
id = idle_ids_stack[old_pos-1];
}
while (!idle_pos.compare_exchange_weak(old_pos, old_pos-1, std::memory_order_acquire, std::memory_order_relaxed));
// wakeup single thread
signal_thread(id);
}
我不是无锁编程方面的专家,但我非常确定您的代码不是线程安全的
寄存器\u idle()
:
这里可能发生的情况是,Thread1递增idle\u pos
,但在它存储其id之前,另一个线程调用wakeup\u一次
,并使用过期的id(在最坏的情况下,甚至是无效的on,因为数组尚未初始化)。我也不明白为什么会有记忆障碍wakeup_one()
中,您会遇到类似的问题(称为:
- 您加载当前的
并根据空闲位置
李>id
- 另一个线程调用并完成唤醒一个线程(空闲位置减少)李>
- 还有一个线程调用寄存器空闲,这会将空闲位置再次增加到与以前相同的值
- 现在第一个线程继续运行,认为空闲线程没有改变,并发出错误线程的信号
除了这些逻辑错误之外,我强烈建议不要使用独立内存围栏(它们会降低代码的可读性,甚至可能会增加成本)。此外,我只会在确保程序与默认顺序正确后才开始手动指定内存顺序。这可能更适合代码审查……您应该很少使用fences。直接同步原子变量。您可能需要使用一些测试工具,例如: