2012-08-03 19 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的线程安全实现的一个很好的例子。