我試圖了解多個執行緒如何在 pop() 中保存頭指標,如果兩個執行緒在“node *old_head = head.load();”處保存頭指標 然后第一個執行緒將通過更新頭部來完成回圈,最后假設我們洗掉了 old_head 并且 Thread1 完成了它的作業,現在 Thread2 仍然持有已洗掉的 old_head 它將進入 while 回圈并且 old_head 和當前頭部不一樣,所以它會去 else if 條件并設定“old_head = head;” 并再次回圈并更新頭部并退出回圈并洗掉 old_head。
在上述程序中,Thread2 永遠不會取消對已洗掉節點的參考,因為如果 head 和 old_head 不同,它將回傳 else if 條件。
但是根據 C ConcurrencyInAction Book 的作者,我們真的需要檢查其他持有 old_head 的執行緒嗎?
來自 C ConcurrencyInAction Book:基本問題是你想釋放一個節點,但你不能這樣做,直到你確定沒有其他執行緒仍然持有指向它的指標。
#include <memory>
#include <atomic>
using namespace std;
template <typename T>
class lock_free_stack
{
private:
struct node
{
std::shared_ptr<T> data;
node *next;
node(T const &data_) : data(std::make_shared<T>(data_))
{
}
};
std::atomic<node *> head;
public:
void push(T const &data)
{
node *const new_node = new node(data);
new_node->next = head.load();
while (!head.compare_exchange_weak(new_node->next, new_node));
}
std::shared_ptr<T> pop()
{
node *old_head = head.load();
while (old_head && !head.compare_exchange_weak(old_head, old_head->next));
// background steps of compare_exchange_weak
/* if ((old_head != nullptr) && (head == old_head))
{
try
{
head = old_head->next;
return true; // loop ends
}
catch(exception &e)
{
return false; // loop forever, at the end if we are deleting old_head then we are deleting head, it makes Stack without head
}
}
else if ((old_head != nullptr) && (head != old_head))
{
old_head = head;
return false;
}
else
{
return false; // loop forever
} */
return old_head ? old_head->data : std::shared_ptr<T>();
}
};
int main()
{
return 0;
}
uj5u.com熱心網友回復:
在上述程序中,Thread2 永遠不會取消對已洗掉節點的參考,因為如果 head 和 old_head 不同,它將回傳 else if 條件。
這不是真的。考慮這一行:
head.compare_exchange_weak(old_head, old_head->next)
這將訪問偶數運行old_head->next之前的值。compare_exchange_weak這意味著如果old_head是一個懸空指標,你會得到Undefined Behavoir。
(請注意,在這種情況下head不等于,因此不會使用的值,但只是在我們知道我們不會使用它之前訪問它已經導致問題)。old_headold_head->next
此外,在您的偽代碼中,您cew似乎認為訪問old_head->next會引發例外?這在c . 訪問一個錯誤的指標將立即導致未定義的行為,這意味著所有的賭注都被取消了。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/430568.html
