无锁有界堆栈C++11原子学
Lock Free Bounded Stack C++11 atomics
我正在考虑使用非常基本的有界(预分配)堆栈来以正确的 LIFO 顺序跟踪我的线程 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 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);
}
我不是无锁编程的专家,但我很确定你的代码不是线程安全的。
-
我们先来看看
register_idle()
:这里可能发生的情况是 Thread1 递增
idle_pos
但在存储其 id 之前,另一个线程调用wakeup_once
并使用过时的 id(在最坏的情况下甚至是无效的 on,因为数组尚未初始化)。我也看不出内存围栏的原因。 -
在
wakeup_one()
您有一个类似的问题(称为ABA问题):- 您加载当前
idle_pos
并根据id
. - 另一个线程调用并完成
wakeup_one
(idle_pos减少)。 - 另一个线程调用
register_idle
,这会再次将idle_pos增加到与以前相同的值。 - 现在第一个线程恢复,认为
idle_pos
没有变化,并发出错误的线程信号
- 您加载当前
我可能弄错了,但我相信通常不可能基于数组创建完全无锁的堆栈,因为您必须在单个原子操作中做两件事:修改索引变量并在数组中存储或加载值。
除了这些逻辑错误之外,我强烈建议不要使用独立的内存围栏(它们使代码的可读性降低,甚至可能更昂贵)。此外,只有在确保程序与默认顺序正确后,我才会开始手动指定内存顺序。
相关文章:
- MSVC是否支持C++11样式的属性而不是__declspec
- 创建LinkedList退出,返回代码为-11(SIGSEGV)
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 如何将模板转换为C++11之前的模板
- c++11评估顺序(未定义的行为)
- C++中的VLA,扩展名为std=C++11
- 代码在我的计算机上运行良好,但是在将其提交给coursera时遇到未知的信号11问题
- "类模板示例<int>;"语句对 C++11 是什么意思?
- this_thread::sleep_for和计时时钟之间的关系是否由C++11标准指定
- 如何使用lock_guard在c++11中实现scoped_lock功能
- C++11 中不同类型的对象的 std::array 的替代方案
- 为什么 -mmacosx-version-min=10.10 不阻止使用标记为从 10.11 开始的函数?
- 为什么我的C++代码中出现'Segmentation Fault: 11'行?
- 在 C++17 中,是否未定义使用无锁原子学保护从信号处理程序传递的数据?
- 此包络实现是否正确使用 C++11 原子学
- 使用 c++11 的并发原语是否有一个体面的wait_any实现?
- C++11原子学:将它们与内存映射的I / O一起使用是否有意义,或者甚至可能
- 在Direct3D 11中绘制具有不同数量原语的对象
- 无锁有界堆栈C++11原子学