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

別のスレッドによって既に破棄されており、null (も null)InvalidArgumentExceptionであるため、StreamWriter を新しくしようとすると、エラーが発生します。メンバー変数をロックするにはどうすればよいですか?m_FileStreamm_StreamWriter

4

3 に答える 3

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 が破棄されることはありません

于 2012-08-03T22:20:01.987 に答える
1

オブジェクトIDisposableインスタンスがDispose()呼び出されたメソッドによって破棄された場合、ガベージ コレクションを保留中の内部状態が破棄されているため、オブジェクト参照は使用できなくなります。

既存のオブジェクト インスタンスを再利用しようとするのではなく、新しいオブジェクト インスタンスをインスタンス化する必要があります。

適切に作成されたオブジェクトは、破棄されたオブジェクトに対して何らかの操作が実行されたときに、特定のサブタイプのInvalidOperationExceptionをスローする必要があります: ObjectDisposedException (ただし、破棄後の呼び出しは例外となる可能性がありDispose()ます)。

IDisposableのドキュメントのコミュニティ コンテンツ セクションには、 IDisposable のスレッドセーフな実装の良い例があります

于 2012-08-03T23:22:12.553 に答える
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();
    }
于 2012-08-03T22:23:11.353 に答える