none
Process.WaitForExit() method inconsistent behaviour

    Question

  • I have checked many forums for inconsistent behaviour of Process.WaitForExit() method but I couldnot identify the real issue. I have the below code

          Process process = new Process();
          process.StartInfo.FileName = AppSettings.BcpExe;
          process.StartInfo.Arguments = args;
          process.StartInfo.CreateNoWindow = false;
          process.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
          logger.InfoFormat("Redirecting BCP process standard error of: {0} to log file", _feedName);
          process.StartInfo.RedirectStandardError = true;       process.StartInfo.UseShellExecute = false;       process.EnableRaisingEvents = true;
          
          process.Exited += new EventHandler(process_Exited);
          process.Start();
          _stderr = process.StandardError.ReadToEnd 
          process.WaitForExit();
          _exitstate = process.ExitCode;
          logger.InfoFormat("Sleeping for: {0} milli secs", BCP_SLEEP);
           Thread.Sleep(BCP_SLEEP);
        
    

    Above code invokes BCP.exe to output data into temp file. This file is then read by two threads (reader and writer) to write to another file after some processing on it. process_Exited method is as follows:

    void process_Exited(object sender, EventArgs e)
        {
          logger.InfoFormat("Error from BCP Process received (if Any): {0}", _stderr.Trim().ToString());
          logger.InfoFormat("Exit State of BCP process: {0}", _exitstate);
          logger.InfoFormat("BCP Completed for: {0}", _feedName);
    
          if (File.Exists(_bcpFileName))
          {
            _feedWriter = new FeedWriter(_feedName);
            _feedWriter.WriteHeader();
    
            Thread reader = new Thread(ReaderThread);
            Thread writer = new Thread(WriterThread);
            reader.Start();
            writer.Start();
            reader.Join();
            writer.Join();
    
            Thread.Sleep(BCP_SLEEP); //Sleep so that files are flushed
          }
          else
          {
            logger.ErrorFormat("BCP file: {0} NOT found after process completion", _bcpFileName);
            Environment.ExitCode = -1;
          }
        }
    

    The issue is that the main thread "SOMETIMES" doesnot wait on process.WaitForExit() method and eventually the main thread sleeps for the time  and then the execution flow moves to the main caller. The Reader thread and Writer Thread just abruptly ends and the file is not processed completely hence the error. Most (95%) of the time this  code works perfectly but it is observed that whenever there is load on the server then we find this inconsistent behaviour and hence the error.

    I am certain that the BCP process runs completely as we have checked the file created by BCP which is complete. I need to know why there is this inconsistent behaviour? The code is complied on .Net3.5 and the Framework on production is .Net3.5 SP1.

    How can this inconsistent behaviour can be solved?

    Thanks for your help.

    Friday, July 15, 2011 6:14 PM

Answers

  • That's not necessarily accurate.

    Consider what would happen if WaitForExit works correctly. Then the process_Exited method is called, but on that first line - before the first line is printed - the computer decides it would be a good time to switch to the other thread. The main thread continues, up to the Sleep line. Once the main thread is sleeping, the process_Completed method continues.

    Keep in mind that the computer can arbitrarily decide to switch threads at any point in time, whenever it wants to. If you have multiple threads running, you can't guarantee that any particular method will be hit before another. Using Sleep isn't a reliable way to synchronize threads, because the OS can jump around any time, not just when you decide to sleep.

    As a side note, in this case you are combining two different ways of checking for the process to exit. If you really want to make sure the process_Completed event is called before the main thread sleeps, why not do them synchronously like this:

    // ...snippet
    process.Start();
    _stderr = process.StandardError.ReadToEnd();
    process.WaitForExit();
    _exitstate = process.ExitCode;
    DoOtherStuff();
    

    Replace your process_Exited event and just put everything in DoOtherStuff(). If your code needs to execute synchronously, the easiest option is just to make it synchronous.


    Check out My Blog for tech news, development tips, and other information for geeks like me.
    • Marked as answer by maverick1979 Friday, July 15, 2011 8:27 PM
    Friday, July 15, 2011 7:48 PM

All replies

  • How do you know that the thread doesnt' wait on WaitForExit()? And what do you actually mean by that - that process_Exited is hit before the _bcpFileName file is created? What's the behavior you're seeing?

    It's perfectly possible that this could just be caused by the threads sleeping at inopportune times.


    Check out My Blog for tech news, development tips, and other information for geeks like me.
    Friday, July 15, 2011 6:58 PM
  • It is because the log message (and time in log message) which shows that Thread.Sleep is called immediately.

     

    Redirecting BCP process standard error of: NAM to log file 

    Sleeping for 10 milliseconds

    Error from BCP Process received (if Any): 0

    Exit State of BCP process: 0

    BCP Completed for: NAM

     

    Logging should be and is when code works fine (and I have checked this logging when the code works fine)

     

    Redirecting BCP process standard error of: NAM to log file 

    Error from BCP Process received (if Any): 0

    Exit State of BCP process: 0

    BCP Completed for: NAM

    Sleeping for 10 milliseconds


    • Edited by maverick1979 Friday, July 15, 2011 7:44 PM Formatting
    Friday, July 15, 2011 7:31 PM
  • That's not necessarily accurate.

    Consider what would happen if WaitForExit works correctly. Then the process_Exited method is called, but on that first line - before the first line is printed - the computer decides it would be a good time to switch to the other thread. The main thread continues, up to the Sleep line. Once the main thread is sleeping, the process_Completed method continues.

    Keep in mind that the computer can arbitrarily decide to switch threads at any point in time, whenever it wants to. If you have multiple threads running, you can't guarantee that any particular method will be hit before another. Using Sleep isn't a reliable way to synchronize threads, because the OS can jump around any time, not just when you decide to sleep.

    As a side note, in this case you are combining two different ways of checking for the process to exit. If you really want to make sure the process_Completed event is called before the main thread sleeps, why not do them synchronously like this:

    // ...snippet
    process.Start();
    _stderr = process.StandardError.ReadToEnd();
    process.WaitForExit();
    _exitstate = process.ExitCode;
    DoOtherStuff();
    

    Replace your process_Exited event and just put everything in DoOtherStuff(). If your code needs to execute synchronously, the easiest option is just to make it synchronous.


    Check out My Blog for tech news, development tips, and other information for geeks like me.
    • Marked as answer by maverick1979 Friday, July 15, 2011 8:27 PM
    Friday, July 15, 2011 7:48 PM
  • Yes I agree, I was mixing Asynchronous and synchronous method call which may give unexpected results.
    Friday, July 15, 2011 8:01 PM