2011-09-14 64 views
4

我正在接管一個C#項目,當測試它時,我收到錯誤。錯誤在於日誌文件無法寫入,因爲它正在被另一個進程使用。下面的代碼:Streamwriter Lock不能正常工作

public void WriteToLog(string msg) 
    { 
     if (!_LogExists) 
     { 
      this.VerifyOrCreateLogFile(); // Creates log file if it does not already exist. 
     } 

     // do the actual writing on its own thread so execution control can immediately return to the calling routine. 
     Thread t = new Thread(new ParameterizedThreadStart(WriteToLog)); 
     t.Start((object)msg); 
    } 

    private void WriteToLog(object msg) 
    { 
     lock (_LogLock) 
     { 
      string message = msg as string; 
      using (StreamWriter sw = File.AppendText(LogFile)) 
      { 
       sw.Write(message); 
       sw.Close(); 
      } 
     } 
    } 

_LogLock被定義爲一個類變量:

private object _LogLock = 0; 

根據我的研究,事實上,這已經在生產系統了幾年,現在做工精細,我不知道問題可能是什麼。該鎖應該防止另一個線程嘗試寫入日誌文件。

我所做的需要測試的更改有更多的日誌使用情況。我們基本上添加了一個調試模式,以便將比以前更多的信息保存到日誌中。

感謝您的幫助!

編輯

感謝您的快速解答! VerifyOrCreateLogFile()的代碼確實使用了_LogLock,所以這不應該成爲問題。在錯誤出來之前,它會對日誌做一些寫操作,所以它通過創建文件就可以了。

什麼似乎是問題是以前只有一個類創建了一個日誌類的實例,現在我已經將實例添加到其他類。這是有道理的,這會造成問題。將_LogLock字段更改爲靜態可以解決問題。

再次感謝!

+1

不僅有那些方法屬於類的單一實例?我問的原因是因爲鎖只會使用相同的實例保護兩個線程。寫入同一個文件的兩個實例會愉快地彼此相向。 – hatchet

+0

@Greg:你可以共享VerifyOrCreateLogFile()方法的代碼,也許它在某些情況下忘記釋放日誌文件句柄?我希望提到的方法在訪問文件時使用_LogLock ... – sll

+1

VerifyOrCreateLogFile()中可能發生異常 - 是否也受保護? – Polyfun

回答

7

該鎖應該阻止另一個線程嘗試寫入日誌文件。

只有當您使用此類的單個實例時纔是如此。

如果每個(甚至某些)日誌請求使用單獨的實例,那麼該鎖定將不會保護您。

您可以輕鬆地通過使_LogLockstatic「糾正」這樣的:

private static object _LogLock = 0; 

這樣一來,所有實例將共享相同的

+0

謝謝,絕對有幫助的信息。我確實添加了日誌類的新實例,當時只有一個實例。但是,在使_LogLock字段爲靜態之後,我仍然在使用該文件的另一個進程中獲得相同的IOException。還有其他建議嗎?我很感激! – Greg

+0

@Greg:其他人使用文件/寫入/讀取它? –

+0

謝謝,我弄明白了,工作。問題是我設置了一個不同的字段LogLock,它是靜態的。將正確的字段_LogLock設置爲靜態可以解決問題。 – Greg

1

一種可能性是操作系統在退出locklock 之前沒有足夠快地釋放文件鎖定,另一個被阻塞的線程在操作系統完成釋放文件鎖定之前嘗試打開它。是的,它可能發生。在嘗試打開文件之前,您需要休眠一會兒,將寫入日誌的文字集中到專用對象(以便他和他只有權訪問此文件,並且不必擔心文件鎖定爭用) 。

另一種可能性是,你需要鎖定圍繞

if (!_LogExists) { 
    this.VerifyOrCreateLogFile(); // Creates log file if it does not already exist. 
} 

第三種可能性是,你有什麼類住房這些方法的多個實例。該鎖對象不會在實例間共享(使其可以通過static來解決)。

在一天結束時,除非您是編寫安全多線程代碼的專家,否則只需讓其他人爲您擔心這個問題。使用爲您處理這些問題的框架(log4net?)。

2

我看到2個問題的代碼:

  • 鎖必須是部份的Log類,最簡單的辦法是所有的「用戶」中同樣做出任何_LogLock或完整的類static
  • VerifyOrCreateLogFile如果2個或更多個並行線程在_LogExists爲假時調用WriteToLog ...
0

您可以通過執行代碼

刪除sw.Close();從你的代碼...

做到這一點.... 它會正常工作.....