2011-09-26 104 views
7

我有一個可以由多個線程創建的類。但是在一個函數中需要保護代碼,所以我決定使用boost進程間互斥。每個班級創建或在它的構造函數打開同一個互斥:Boost named_mutex和remove()命令

MyClass::MyClass() 
{ 
     boost::interprocess::named_mutex m_Lock(
       boost::interprocess::open_or_create, "myLock"); 
} 

所以現在來這裏的關鍵代碼部分被稱爲點:

int MyClass::MyFunction() 
{ 
     boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(
        m_Lock, boost::interprocess::try_to_lock); 
     if(!lock) 
     { 
      return -1; 
     } 
     // else do some stuff here 
} 

給函數清理乾淨後(和喜歡它升壓頁中介紹)我在類​​析構函數使用remove命令:

MyClass::~MyClass() 
{ 
     boost::interprocess::named_mutex::remove("myLock"); 
} 

其實這一切的代碼工作正常,但有一個關心我:

正如它在刪除命令的描述是說:

擦除從系統中命名的mutex。錯誤返回false。永遠不會拋出。

因此,這意味着刪除命令只是從系統中刪除互斥體 - 即使另一個線程剛剛鎖定它(我已經試過這種情況 - 它不再鎖定)。 所以我的問題如下: 例如我有3個線程(A,B和C) - 現在將出現以下情況:

  1. 方法A創建該類的一個實例,調用函數,並鎖定它
  2. 方法B創建該類的一個實例,調用該函數,但不能訪問代碼(隨後等待例如)
  3. 方法A與受保護的代碼完成和它被解鎖
  4. 方法B獲得對受保護的代碼並鎖定它
  5. 過程s A刪除類的實例 - >刪除命令被調用
  6. 進程C創建類的實例,調用該函數並可以訪問代碼,因爲remove命令刪除了Mutex - > Error!

所以現在有人可能會說「那麼不要刪除!」 - 那可能嗎?我的意思是自named_mutex寫入系統後,我懷疑它沒有明確的調用就被擦除,即使程序結束。 任何人都有一些幫助?

+0

我很困惑你的問題和術語「線程」和「過程」的相互使用。你在打哪個?線程?或進程?如果你只在一個單獨的進程中使用多線程,那麼命名的模式通常具有非常小的效用。 –

+0

對此感到抱歉 - 寫作時我有點兒困惑。其實我有不同的過程。正如你所說的,只有線程不需要命名互斥體。 – Toby

回答

6

boost docsremove調用是不必要的。 named_mutex的析構函數會自動注意向操作系統指出進程不再需要該資源。你只需依靠析構函數的內置行爲來清理就可以了。

如果您明確調用remove,您可能會導致任何其他進程或線程嘗試使用指定的互斥對互斥量上的任何操作執行失敗。根據您的使用情況如何編排,這可能會導致數據競爭或在其他進程中拋出異常/異常。

〜named_mutex();

銷燬* this並指示使用該資源完成調用過程 。析構函數將釋放系統分配的任何系統資源以供此過程用於此 資源。資源仍然可以再次打開,調用構造函數重載的開放 。要從系統中清除資源,請使用 remove()。

+0

因此,如果我沒有弄錯,只要我不調用remove(),資源就會留在系統中(即使析構函數被調用) - 但這並不重要,因爲析構函數告訴操作系統資源是「解鎖「,所以另一個進程可以鎖定它?這是對的嗎? – Toby

+0

我自己也沒有和他們一起玩過,但我認爲如果使用互斥鎖的進程數量爲零,資源將被釋放。 sem_close()關閉sem引用的命名信號量,允許系統分配給調用進程 的任何資源釋放此信號量。 –

+10

好吧,我昨天做了一些調查和反覆試驗。互斥體的資源位於共享內存(/ dev/shm /)中。創建後,它將保持在那裏,直到您調用remove()或系統重新啓動。 (或者你做任何其他事情來清除共享內存,例如自己擦除它)。該對象本身包含有關其是否被鎖定的信息。當互斥體被破壞時,它會被解鎖但不會被擦除!所以唯一的問題可能是程序崩潰,無法調用析構函數並且對象保持鎖定狀態。 – Toby

0

您可能需要共享的互斥量使用計數器。在析構函數中鎖定互斥鎖,將其減1,如果在遞減之後爲零,則釋放仍然鎖定的互斥鎖。你會通過這種方式來阻止你目前的比賽狀況。