2012-08-03 93 views
0

我簡化了這個代碼示例目的:如何鎖定成員變量?

class TextLogger : IDisposable 
{ 
    private FileStream m_FileStream; 
    private StreamWriter m_StreamWriter; 

    void CreateNewLogFile() 
    { 
      //Open the File 
     m_FileStream = File.Open(
      m_CurrentFileName, 
      FileMode.OpenOrCreate, 
      FileAccess.Write, 
      FileShare.Read); 

     m_StreamWriter = new StreamWriter(m_FileStream); 
     .... 
    } 
} 

嘗試新出的StreamWriter當我得到一個InvalidArgumentException,因爲m_FileStream已被釋放被另一個線程,而空(m_StreamWriter也爲空)。我如何鎖定成員變量?

+0

你在哪裏分配m_FileStream你正在創建一個空值流它顯示..你有你從問題中省略的額外代碼..? – MethodMan 2012-08-03 22:18:49

+0

你在哪裏創建初始FileStream ..? – MethodMan 2012-08-03 22:21:03

+0

@DJKRAZE - 我有它正確的上面(見編輯) – 2012-08-03 22:24:31

回答

2

你應該做這樣的事情

class TextLogger : IDisposable 
{ 
    private FileStream m_FileStream; 
    private StreamWriter m_StreamWriter; 
    private object m_Lock = new object(); 

    void CreateNewLogFile() 
    { 
     lock (m_Lock) 
     { 
      if (m_FileStream != null) 
       m_StreamWriter = new StreamWriter(m_FileStream); 
     }; 
    } 

    void CalledFromOtherThread() 
    { 
     //Do stuff 

     lock (m_Lock) 
     { 
      if (m_FileStream != null) 
       m_FileStream.Dispose(); 
      m_FileStream = null; 
     } 
    } 
} 

CalledFromOtherThread從另一個線程調用它應該獲得的鎖,然後處置m_FileStream。這樣,在CreateNewLogFile你將永遠不會有一個配置的FileStream

+0

那麼調用者應該負責調用dispose? – 2012-08-03 22:36:57

+0

無論誰打電話都應該獲得鎖定。這可以確保您的m_FileStream是** null或有效** – 2012-08-03 22:42:52

1

ThreadLocal更好

static void Main() 
    { 
     // Thread-Local variable that yields a name for a thread 
     ThreadLocal<string> ThreadName = new ThreadLocal<string>(() => 
     { 
      return "Thread" + Thread.CurrentThread.ManagedThreadId; 
     }); 

     // Action that prints out ThreadName for the current thread 
     Action action =() => 
     { 
      // If ThreadName.IsValueCreated is true, it means that we are not the 
      // first action to run on this thread. 
      bool repeat = ThreadName.IsValueCreated; 

      Console.WriteLine("ThreadName = {0} {1}", ThreadName.Value, repeat ? "(repeat)" : ""); 
     }; 

     // Launch eight of them. On 4 cores or less, you should see some repeat ThreadNames 
     Parallel.Invoke(action, action, action, action, action, action, action, action); 

     // Dispose when you are done 
     ThreadName.Dispose(); 
    } 
1

如果您IDisposable對象實例已經被其Dispose()方法處置被調用時,對象引用爲—或應—不再可用,因爲其內部狀態已被銷燬,正在進行垃圾回收。

您應該實例化一個新的對象實例,而不是試圖重用現有的對象實例。當釋放的對象上執行的任何操作

一個精心設計對象應該拋出的InvalidOperationException特定亞型:(與Dispose()處置後調用的可能的例外)ObjectDisposedException

IDisposable的文檔具有在社區內容部分爲IDisposable的線程安全實現的一個很好的例子。