我一直在想如何實現一個無鎖的單向鏈表。說實話,我沒有看到許多防彈的方法來做到這一點。即使更強大的方式使用CAS
結束了一定程度的ABA problem。因此,我不得不去思考。部分無鎖系統不會比總是使用鎖更好嗎?可能有些操作可以是原子的並且無鎖定的?如果我能做到這一點,它應該仍然是線程安全的。test_and_set線程的這種用法是否安全?
因此,到問題。我正在考慮一個簡單的單鏈表。 2個主要業務。 push
和pop
。 push
總是插在前面。類似這樣的:
void push(int n) {
T *p = new T;
p->n = n;
p->next = root;
root = p;
}
而彈出總是需要第一個元素。像這樣的:
T *pop() {
T *p = root;
root = root->next;
return p;
}
顯然推是不夠平凡,一個簡單的無鎖方法可能不會發生。但流行看起來可能是可行的。使用gcc-內在我已經想到了這一點:
T *pop() {
return __sync_lock_test_and_set(&root, root->next);
}
功能等同的?對。無鎖?對。線程安全? 我不知道。我的直覺反應是否定的,這是爲什麼。
我擔心的是test_and_set
的其中一個參數必須對內存進行解引用。如果根目錄在root->next
和__sync_lock_test_and_set
之間改變,該怎麼辦?
我想,這個代碼是相同的:
T *pop() {
T *temp = root->next;
// are we broken if a push/pop happens here?
return __sync_lock_test_and_set(&root, temp);
}
所以,就像我說的,我覺得此代碼是不正確的。但是有誰能夠肯定地說我正在得出正確的結論(我討厭寫出一些很好的東西)。如果它真的被破壞,我懷疑。有沒有簡單的解決方案?
當然,空列表上的彈出顯然是未定義的行爲。但這對於真正的問題有點問題。 – 2010-05-24 21:22:26