我已将此代码简化为示例目的:
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 :(得分: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
答案 1 :(得分:1)
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();
}
答案 2 :(得分:1)
如果您的IDisposable
对象实例已被其被调用的Dispose()
方法处理掉,则对象引用是 - 或应该 - 不再可用,因为其内部状态已被销毁,等待垃圾回收。
您应该实例化一个新的对象实例,而不是尝试重用现有的对象实例。
当对已处置的对象执行任何操作时,精心设计的对象应抛出InvalidOperationException的特定子类型:ObjectDisposedException(Dispose()
的后置处置调用可能除外。)
IDisposable的文档在社区内容部分中提供了IDisposable的线程安全实现的一个很好的示例。