2010-02-12 120 views
9

下面的代碼包含潛在的死鎖,但似乎是必要的:要將數據安全地從另一個容器複製到一個容器,必須鎖定兩個容器以防止在另一個線程中發生更改。獲取對兩個互斥鎖的鎖定並避免死鎖

void foo::copy(const foo & rhs) 
{ 
    pMutex->lock(); 
    rhs.pMutex->lock(); 
    // do copy 
} 

Foo有一個STL容器,「do copy」基本上由使用std :: copy組成。如何在不引入死鎖的情況下鎖定兩個互斥鎖?

回答

15

foo的實例上強加某種總訂單,並始終以遞增或遞減的順序獲取其鎖定,例如foo1->lock(),然後foo2->lock()

另一種方法是使用功能語義,而不是寫一個foo::clone方法,該方法創建一個新的實例,而不是翻轉現有的實例。

如果您的代碼執行大量鎖定,則可能需要複雜的死鎖避免算法,如banker's algorithm

+0

即使是一些作爲本VS RHS地址一樣簡單會工作。請務必首先鎖定低位地址。 – 2010-02-12 04:24:23

+0

克隆只有在不復制的情況下才能正常工作,並且我不認爲隱式共享會起作用,但我會看一看。 有趣的方法凱爾。我看不到任何缺陷。 – pomeroy 2010-02-12 20:49:01

1

這個怎麼樣?

void foo::copy(const foo & rhs) 
{ 
    scopedLock lock(rhs.pMutex); // release mutex in destructor 
    foo tmp(rhs); 
    swap(tmp); // no throw swap locked internally 
} 

這是異常安全的,而且線程安全。要100%線程保存,您需要查看所有代碼路徑,然後再次使用另一組眼睛重新查看,之後再次查看它...

-1

爲了避免死鎖,它可能是最好的,等到這兩種資源都可以鎖定:

不知道該互斥您使用所以這裏API是一些任意的僞代碼,假設can_lock()只有檢查它是否可以鎖定一個互斥體,而try_lock()返回true,如果它沒有鎖,而假,如果互斥鎖已被其他人鎖定。

void foo::copy(const foo & rhs) 
{ 
    for(;;) 
    { 
     if(! pMutex->cany_lock() || ! rhs.pMutex->cany_lock()) 
     { 
      // Depending on your environment call or dont call sleep() 
      continue; 
     } 
     if(! pMutex->try_lock()) 
      continue; 
     if(! rhs.pMutex->try_lock()) 
     { 
      pMutex->try_lock() 
      continue; 
     } 
     break; 
    } 
    // do copy 
} 
+2

爲了避免死鎖,最好引入一個活鎖?並旋轉,使用100%的CPU? – bk1e 2010-02-13 05:17:40

-1

您可以嘗試使用的scoped_lock或auto_lock同時鎖定兩個互斥....像銀行轉賬做...

void Transfer(Receiver recv, Sender send) 
{ 
    scoped_lock rlock(recv.mutex); 
    scoper_lock slock(send.mutex); 

    //do transaction. 
}