关于 lockfree 算法
lockfree的本質是樂觀鎖。也就是說,它假設多數情況下,別人不會改變。一個通用的lockfree算法可描述如下:
?
lockfree_modify(DataT* data)
{
??? for (;;)
??? {
??????? Save old state of data to a local variable;
??????? do modify;
??????? lock {
??????????? if (current state == old state)
??????????????? commit modify & return;
??????? }
??? }
}
?
可以看出,lockfree也是鎖,只是將鎖限制在一個最小的范圍內(通常是一個原子操作)。由于仍然有鎖,lockfree在多核下并不會比普通的鎖高明多少,它也不能隨cpu個數增加而獲得呈線性scale的性能提升。
?
不過,lockfree有個最大的好處,就是不可能有死鎖。因為對上面算法分析你可以知道,在某個線程modify失敗,總意味著有另一個人成功了,整個程序總在一步步前進,而不是出現相互等待而產生饑餓的狀況。
?
我們以stack為例,展示下lockfree的stack是怎樣的:
?
class stack
{
public:
?struct Node
?{
? Node* prev;
?};
?
private:
?Node* m_head;
?
public:
?stack()
? : m_head(NULL)
?{
?}
?
?void push(Node* val)
?{
? for (;;)
? {
?? Node* head = m_head;
?? val->prev = head;
?? if (InterlockedCompareExchangePointer((PVOID*)&m_head, val, head) == head)
??? return;
? }
?}
?
?Node* pop()
?{
?? for (;;)
?? {
???? Node* head = m_head;
???? if (head == NULL)
?????? return NULL;
???? if (InterlockedCompareExchangePointer((PVOID*)&m_head, head->prev, head) == head)
???????? return head;
?? }
?}
};
?
嗯,看起來挺不錯,代碼還算優雅。。。不過遺憾的是,嚴謹的說其實上面的lockfree算法是有問題的。問題在哪里?在pop算法上。我們看lock范圍內的語義:
?
???? if (InterlockedCompareExchangePointer((PVOID*)&m_head, head->prev, head) == head)
???????? return head;
?
這句話用偽代碼描述是:
?
???? lock {
???????? if (m_head == head) {
????????????? m_head = head->prev;
????????????? return head;
???????? }
???? }
?
問題在于,m_head指針的值沒有發生變化,和整個stack沒有發生變化,這兩者等價嗎?
?
不等價。完全可以發生一種情況就是,另一個線程執行了這樣一段代碼:
?
??? v1 = pop();? // v1是m_head
??? v2 = pop();
??? push(v1);
?
此時,m_head沒有變化,但是m_head->prev不再是v2,而是v2->prev了。
?
那么怎么辦?在說解決方案前,我們先再聊下上例中的stack::push。既然stack::pop有問題,那么stack::push呢?我們說,push算法的并沒有什么問題。盡管同樣的,m_head指針的值沒有發生變化,并不意味著整個stack沒有發生變化。但是對于push來說,它只關心m_head,而不關心其他東西,所以stack是否發生變化對其并無影響。
?
那么,應該如何解決pop算法遇到的問題?一個比較通用的方法,就是版本號。lockfree算法中,有一個術語叫tagged_ptr,其實本質上就是一個打了版本號的pointer:
?
??? struct tagged_ptr
??? {
??????? void* p;
??????? size_t tag;
??? };
?
每次要對p進行修改,都++tag。這樣,判斷是不是modify,只需要判斷tag是否變化即可。
?
lockfree小結:
- 優點:不發生死鎖。性能通常比lock好一些。
- 缺點:仍然是鎖。所以并不能隨cpu個數增加而獲得呈線性scale的性能提升。
- 缺點:lockfree算法的實現通常比較復雜,不利于推廣到任意算法的lockfree改造。通常只有少量庫代碼使用lockfree。
轉載于:https://www.cnblogs.com/wuwuwu/archive/2009/05/02/6162381.html
總結
以上是生活随笔為你收集整理的关于 lockfree 算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 麻省理工学院(MIT)的公开课程
- 下一篇: 励志英语谚语【二】