2012-02-06 126 views
8

我不斷從內存映射文件讀取另一個進程正在寫入並使用互斥鎖來同步此操作。在我迄今爲止的一些測試中,這種方法工作得很好,但是......如果我的應用程序在獲取互斥體之後並在發佈之前崩潰了,該怎麼辦?有什麼辦法可以保證互斥體的釋放,即使在這樣的崩潰的情況下?「安全」處理互斥鎖?

另外我該如何處理另一個進程的崩潰,這可能還沒有釋放互斥量呢?每次我調用mutex.WaitOne()時,是否需要處理AbandonedMutexException?

現在我正在做與此類似:

public MyState GetState() 
{ 
    MyState state = new State(); 
    this._mutex.WaitOne(); 
    try 
    { 
     state.X = this._mmView.ReadSingle(0); 
     state.Y = this._mmView.ReadSingle(4); 
     [..] 
    } 
    finally 
    { 
     this._mutex.ReleaseMutex(); 
    } 
    return state; 
} 

_mmView是MemoryMappedViewAccessor我之前實例化。整個方法GetState()被稱爲每個幀作爲遊戲循環的一部分,因此大約每幾毫秒。

PS:另外,還有沒有其他明顯的問題,爲什麼這可能會失敗,我沒有提到?

回答

11

尤金的答案是正確的 - 操作系統將釋放互斥鎖爲您服務。現在,認真思考什麼樣的這一事實的後果是:

  • 你拿出互斥體,以確保沒有人會發生變異狀態,而你讀,或閱讀狀態,而你正在變異。我們假設後者。
  • 另一個應用程序想讀取狀態,所以它試圖採取互斥體。它被迫等待。
  • 你突變了一些狀態然後崩潰。
  • 操作系統發佈互斥鎖。
  • 另一個應用程序現在立即獲取互斥鎖,現在正在有效讀取狀態「,而」另一個進程正在突變它。事實上,另一個過程現在已經死了,這意味着假現狀將永遠持續,閱讀過程本身可能會崩潰並死亡。 您剛剛擊敗了互斥鎖提供的安全系統。

總之,你正在擔心錯誤的東西。你應該不會擔心如果我的互斥鎖從未發佈過會發生什麼情況。發生的最糟糕的事情是每個人都會永遠等待,這很讓人傷心,但最終用戶會重新啓動機器。你應該擔心如果互斥確實得到釋放,因爲我在突變中途墜毀,會發生什麼情況。在這種情況下,進程現在可能會在整個地方崩潰,並且用戶的數據將永久損壞

首先不要進入這種情況。解決這個問題的方法是當你爲寫入而取出一個互斥鎖時不會崩潰。如果你不寫程序崩潰,那麼你不必擔心它,因爲它不會發生。所以只是不寫編程有史以來崩潰。

+3

「不要編寫有史以來崩潰的程序」,或者像禪師說的那樣 - 「避免錯誤」。偉大的建議。啊哈。 – mickeyf 2012-02-07 00:03:14

+1

雖然聽起來不太健壯也不現實。如果用戶通過任務管理器簡單地殺死進程,強行崩潰應用程序會怎樣? – Mario 2012-02-07 00:39:48

+7

@Mario:我不知道你認爲什麼是不現實的;我向你保證,這些數據損壞錯誤會頻繁出現,如果你關心用戶數據的狀態,就必須對其進行保護。 Re:如果用戶崩潰應用程序會怎麼樣?你問我當用戶做了什麼破壞他們自己的數據會發生什麼? **他們的數據被破壞**,這就是事實。不希望自己的數據被破壞的用戶**不應該關閉他們的應用**。有一個*理由*爲什麼這樣做會出現一個對話框,指出「如果你這樣做,你可能會破壞你的數據」。 – 2012-02-07 00:43:42

2

當一個進程結束時擁有一個互斥鎖,OS會自動爲你釋放互斥鎖。通過獲取互斥體試試這個,然後raise new WhateverException() - 另一個過程將繼續。

這同樣適用於所有的同步原語真AFAIK