-1

I have a method in my program and need to know if it is threadsafe. I am getting System.I.O exception writing to this file though it is not very consistent which terminates my program

There is file location mentioned outside the method.

private readonly string fileNameAndPath = @"C:\Apps\TestService\log\Test.txt";

public void LogRequestDetails_SendOrderRequestMethod(Message request, SendOrderRequest quoteRequest)
{
    // Create a writer and open the file:
    StreamWriter log;

    if (!File.Exists(fileNameAndPath))
           log = new StreamWriter(fileNameAndPath);
    else
           log = File.AppendText(fileNameAndPath);

    // Write to the file:
    log.WriteLine("=================================");
    log.WriteLine(DateTime.Now);
    log.WriteLine("Price : " + quoteRequest.Price);
    log.WriteLine("QuoteId : " + quoteRequest.QuoteId);
    log.WriteLine("SecurityId : " + quoteRequest.SecurityId);
    log.WriteLine();
    log.WriteLine("Request string : " + request.ToString());
    log.WriteLine("=================================");
    log.WriteLine("\n");

    // Close the stream:
    log.Close();
}

Please see the stack trace below

Application: BestInvest.Select.ShareDealingService.exe

Framework Version: v4.0.30319

Description: The process was terminated due to an unhandled exception.

Exception Info: System.IO.IOException

Stack:



Server stack trace: 

   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)

   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)

   at System.IO.StreamWriter.CreateFile(String path, Boolean append, Boolean checkHost)

   at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding, Int32 bufferSize, Boolean checkHost)

   at System.IO.StreamWriter..ctor(String path, Boolean append)

   at System.IO.File.AppendText(String path)

   at BestInvest.Direct.Integration.FIXService.ShareDealingEngine.LogRequestDetails_SendOrderRequestMethod(Message request, SendOrderRequest quoteRequest)

   at BestInvest.Direct.Integration.FIXService.ShareDealingEngine.<>c__DisplayClass5.<SendOrder>b__2()

   at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs)

   at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)

   at System.Runtime.Remoting.Proxies.RealProxy.EndInvokeHelper(System.Runtime.Remoting.Messaging.Message, Boolean)

   at System.Runtime.Remoting.Proxies.RemotingProxy.Invoke(System.Object, System.Runtime.Remoting.Proxies.MessageData ByRef)

   at System.Action.EndInvoke(System.IAsyncResult)

   at System.Runtime.Remoting.Messaging.AsyncResult.SyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage)

   at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage, System.Runtime.Remoting.Messaging.IMessageSink)

   at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(System.Object)

   at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)

   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)

   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)

   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()

   at System.Threading.ThreadPoolWorkQueue.Dispatch()

   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Tom
  • 8,175
  • 41
  • 136
  • 267
  • What if two threads call the method simultanously? In that case you can get a mess of two log records (e.g. 1st thread writes 3 lines, then the 2nd thread writes 2 lines and then1st agian) – Dmitry Bychenko Nov 13 '15 at 13:01

2 Answers2

1

it is not thread safe. You can protect critical sections of your code from race conditions by employing locks.

private readonly string fileNameAndPath = @"C:\Apps\TestService\log\Test.txt";

private Object thisLock = new Object();

public void LogRequestDetails_SendOrderRequestMethod(Message request, SendOrderRequest quoteRequest)
{
  lock (thisLock)
  {
     // Create a writer and open the file:
     StreamWriter log;

     if (!File.Exists(fileNameAndPath))
       log = new StreamWriter(fileNameAndPath);
     else
       log = File.AppendText(fileNameAndPath);

     // Write to the file:
     log.WriteLine("=================================");
     log.WriteLine(DateTime.Now);
     log.WriteLine("Price : " + quoteRequest.Price);
     log.WriteLine("QuoteId : " + quoteRequest.QuoteId);
     log.WriteLine("SecurityId : " + quoteRequest.SecurityId);
     log.WriteLine();
     log.WriteLine("Request string : " + request.ToString());
     log.WriteLine("=================================");
     log.WriteLine("\n");

     // Close the stream:
     log.Close();
 }
}

for more details please see references: https://msdn.microsoft.com/en-us/library/a8544e2s.aspx

Aqdas
  • 868
  • 4
  • 16
  • 57
0

I think File.Exists and File.AppendText are thread safe as they are static calls.

However, instance method calls to StreamWriter.WriteLine wouldn't be so I think it's possible for one thread to be writing to the file and another to try and append before the first thread has finished which could lead to an exception.

Or indeed two threads could try and write to the file using the StreamWriter at the same time.

What is the exact message on the System.IOException?

MattC
  • 3,984
  • 1
  • 33
  • 49