C# 如何锁定成员变量?

C# 如何锁定成员变量?,c#,multithreading,locking,C#,Multithreading,Locking,出于示例目的,我简化了此代码: class TextLogger : IDisposable { private FileStream m_FileStream; private StreamWriter m_StreamWriter; void CreateNewLogFile() { //Open the File m_FileStream = File.Open( m_CurrentFileName,

出于示例目的,我简化了此代码:

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
已经被另一个线程处理,并且为null(
m_StreamWriter
也为null)。如何在成员变量周围设置锁?

您应该这样做

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;
        }
    }
}

当从其他线程调用
时,它应该获取锁,然后处理m_文件流。这样,在
CreateNewLogFile
中,您将永远不会有一个已处理的文件流

您应该这样做

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;
        }
    }
}
当从其他线程调用
时,它应该获取锁,然后处理m_文件流。这样,在
CreateNewLogFile
中,您将永远不会有一个已处理的文件流

更好

 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();
    }
static void Main()
{
//生成线程名称的线程局部变量
ThreadLocal ThreadName=新的ThreadLocal(()=>
{
返回“Thread”+Thread.CurrentThread.ManagedThreadId;
});
//打印当前线程的ThreadName的操作
动作动作=()=>
{
//如果ThreadName.IsValueCreated为true,则表示我们不是
//在此线程上运行的第一个操作。
bool repeat=ThreadName.IsValueCreated;
WriteLine(“ThreadName={0}{1}”,ThreadName.Value,repeat?”(repeat)”:“”);
};
//启动其中八个。在4个内核或更少的内核上,您应该会看到一些重复的线程名称
并行调用(动作,动作,动作,动作,动作,动作,动作,动作,动作);
//完成后处理
ThreadName.Dispose();
}
这一点更好

 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();
    }
static void Main()
{
//生成线程名称的线程局部变量
ThreadLocal ThreadName=新的ThreadLocal(()=>
{
返回“Thread”+Thread.CurrentThread.ManagedThreadId;
});
//打印当前线程的ThreadName的操作
动作动作=()=>
{
//如果ThreadName.IsValueCreated为true,则表示我们不是
//在此线程上运行的第一个操作。
bool repeat=ThreadName.IsValueCreated;
WriteLine(“ThreadName={0}{1}”,ThreadName.Value,repeat?”(repeat)”:“”);
};
//启动其中八个。在4个内核或更少的内核上,您应该会看到一些重复的线程名称
并行调用(动作,动作,动作,动作,动作,动作,动作,动作,动作);
//完成后处理
ThreadName.Dispose();
}

如果您的
IDisposable
对象实例已被调用的
Dispose()
方法处置,则对象引用将不再可用,或者应该不再可用,因为其内部状态已在挂起垃圾回收期间被破坏

您应该实例化一个新的对象实例,而不是试图重用现有的对象实例

当对已处置对象执行任何操作时,精心编制的对象应抛出的特定子类型:(处置后调用
Dispose()
可能除外)


社区内容部分中的文档提供了线程安全实现的一个很好的示例。

如果您的
IDisposable
对象实例已通过调用其
Dispose()
方法处理,对象引用不再可用,或者应该不再可用,因为其内部状态已在挂起垃圾回收时被破坏

您应该实例化一个新的对象实例,而不是试图重用现有的对象实例

当对已处置对象执行任何操作时,精心编制的对象应抛出的特定子类型:(处置后调用
Dispose()
可能除外)


社区内容部分中的文档提供了线程安全实现的一个很好的示例。

您在哪里分配m_FileStream?您正在创建一个空流。它出现了。。您是否有从问题中遗漏的其他代码..?您在哪里创建初始文件流..?@DJKRAZE-我在上面有它(请参见编辑)看起来仍然会导致错误您在哪里定义或传入m_CurrentFileName..?您在哪里分配m_文件流?您正在创建一个空流它出现。。您是否有从问题中遗漏的其他代码..?您在何处创建初始文件流..?@DJKRAZE-我在上面有它(请参见编辑)看起来仍然会导致错误您在何处定义或传入m_CurrentFileName..?因此调用方应负责调用dispose?调用方应获得锁。这可确保m_文件流为null或有效,因此调用方应负责调用dispose?调用方应获得锁。这将确保m_文件流为null或有效