Probable I/O race condition detected while copying memory

Topics: Logging Application Block
Sep 2, 2013 at 4:55 PM
Hi,
i'm using the Logging application block from EntLib5 and, at least once a day, I receive this error :
Exception Type: System.IndexOutOfRangeException
Message: Probable I/O race condition detected while copying memory. The I/O package is not thread safe by default. In multithreaded applications, a stream must be accessed in a thread-safe way, such as a thread-safe wrapper returned by TextReader's or TextWriter's Synchronized methods. This also applies to classes like StreamWriter and StreamReader.
Data: System.Collections.ListDictionaryInternal
TargetSite: Void InternalBlockCopy(System.Array, Int32, System.Array, Int32, Int32)
HelpLink: NULL
Source: mscorlib

Following the method i use to log :
public static void DebugEvent(string message)
        {
            using (var lw = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>())
            {
                var le = new LogEntry();
                le.Categories.Add(DEBUG_CATEGORY);
                le.Message = message;
                le.Severity = TraceEventType.Verbose;
                lw.Write(le);
            }
        }
Where am I wrong ?
Thanks,

Fabio
Sep 2, 2013 at 8:09 PM
The issue is occurring because the LogWriter instance is being disposed on every call to DebugEvent. In a multi-threaded environment this can cause issues. The LogWriter is a singleton which you shouldn't need to dispose on every logging call (unless you have a good reason to such as an explicit programmatic reconfiguration).

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Sep 27, 2013 at 10:29 PM
lw is being disposed, but surely the underlying LogWriter instance remains, and therefore it's destructor isn't called?
Why does that cause an issue, what am I missing?
Sep 28, 2013 at 12:17 AM
When the LogWriter is Disposed it calls Dispose on all the LogSources.
When a LogSource is Disposed it calls Dispose on all of the trace listeners configured for the LogSource.
When Dispose is called on a trace listener such as the TextWriterTraceListener, the underlying TextWriter is closed.

Bear in mind that LogWriter.Write is thread-safe but calling Dispose is not thread-safe. So what can happen is that while Thread 1 is writing, Thread 2 is waiting to write (because Write is thread-safe) but Thread 3 is calling Dispose on the LogWriter which closes the underlying TextWriter and causes an issue.

So the sequence of calls looks like this:
LogWriter.Dispose
  LogSource.Dispose
    TraceListener.Dispose
      TraceListener.Close
        TextWriter.Close
But if the TextWriter is Disposed then why can we continue logging? The reason is that before logging any message the TextWriterTraceListener checks if the TextWriter is null and if so it will open the stream (again).

So to sum up:
  • Dispose is not thread-safe
  • There is not usually a reason to call Dispose on the LogWriter singleton (the one exception is if you wish to close all files in order to reconfigure the block)
~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to