[英]Lock-free stack - Is this a correct usage of c++11 relaxed atomics? Can it be proven?
[英]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()
:
此處可能發生的事情是idle_pos
遞增了idle_pos
但是在它存儲其ID之前,另一個線程調用了wakeup_once
並使用了過時的ID(在最壞的情況下,甚至是無效的,因為該數組尚未初始化)。 我也看不出內存隔離的原因。
在wakeup_one()
您有一個類似的問題(稱為ABA問題 ):
idle_pos
並根據id
加載。 wakeup_one
(idle_pos減少了)。 register_idle
,它再次將idle_pos增加到與以前相同的值。 idle_pos
不變,並發出錯誤的線程信號 我可能會弄錯了,但我相信通常無法基於數組創建完全無鎖的堆棧,因為您必須在單個原子操作中做兩件事:修改索引變量並將值存儲或加載到數組中。陣列。
除了這些邏輯錯誤之外,我強烈建議不要使用獨立的內存隔離柵(它們會使代碼的可讀性降低,甚至可能導致成本更高)。 另外,在確保程序正確且默認設置正確之后,我只會開始手動指定內存順序。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.