![](/img/trans.png)
[英]Why does nvmlDeviceGetTemperature only work in debug mode?
[英]Why does program only work with debugging mode?
我試圖了解無鎖編程,並寫了一個無鎖堆棧:
template <typename T>
class LockFreeStack
{
struct Node
{
std::shared_ptr<T> data;
Node* next;
explicit Node(const T& _data)
: data(std::make_shared<T>(_data)), next(nullptr)
{}
};
std::atomic<Node*> head;
public:
void push(const T& data)
{
auto n{new Node(data)};
n->next = head.load();
while (!head.compare_exchange_weak(n->next, n))
;
}
std::shared_ptr<T> pop(void)
{
auto old_head{head.load()};
while (old_head && head.compare_exchange_weak(old_head, old_head->next))
;
return old_head ? old_head->data : std::shared_ptr<T>{};
}
};
以及兩個用於推送/彈出操作的線程:
static LockFreeStack<int> global_stack;
和main
功能:
int main(void)
{
std::srand(std::time(nullptr));
std::thread pushing_thread([](void) {
for (size_t i{}; i < MAX_LENGTH; ++i)
{
const auto v{std::rand() % 10000};
global_stack.push(v);
std::cout << "\e[41mPoping: " << v << "\e[m" << std::endl;
}
});
std::thread poping_thread([](void) {
for (size_t i{}; i < MAX_LENGTH; ++i)
{
if (auto v{global_stack.pop()}; v)
{
std::cout << "\e[42mPushing: " << *v << "\e[m" << std::endl;
}
}
});
pushing_thread.join();
poping_thread.join();
}
該程序僅在調試模式下運行pushing_thread
,但是當我使用調試器運行該程序時,它會按預期運行兩個線程,或者如果我在線程之間等待片刻:
std::thread pushing_thread(...);
std::this_thread::sleep_for(1s);
std::thread poping_thread(...);
它工作正常。 那么當我們用調試器運行程序時會發生什么呢?
GCC 9.3
。-std=c++2a -lpthread -Wall
。ArchLinux with linux-5.5.13
。這個邏輯有問題:
while (old_head && head.compare_exchange_weak(old_head, old_head->next))
;
如果 old_head 不為空並且交換成功,則再試一次!
您的實現存在所謂的 ABA 問題。 考慮以下場景:
A->B->C
(即頭指向 A)A
的地址)和A
的下一個指針( B
),但在它可以執行 CAS 之前,它被中斷了。A
,然后B
,然后壓入A
,即堆棧現在看起來像這樣: A->C
A
更新到B
-> 您的堆棧已損壞 - 看起來像這樣: B->C
- 但B
當前正在被線程 2 使用。有幾種可能的解決方案可以避免 ABA 問題,例如標記指針或並發內存回收方案。
更新:
標記指針只是一個用版本計數器擴展的指針,每次更新指針時版本標記都會增加。 您可以使用 DWCAS (Double-Width-CAS) 來更新具有單獨版本字段的結構,或者您可以將版本標記壓縮到指針的高位。 並非所有架構都提供 DWCAS 指令(x86 提供),如果高位未使用,則取決於操作系統(在 Windows 和 Linux 上,通常可以使用最高 16 位)。
關於內存回收方案的主題,我可以向您推薦我的論文: C++ 中無鎖數據結構的有效內存回收
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.