3

I have console .NET application that is intended for execution of test automation.

Application invokes a separate thread from the main thread and in that new thread executes automated script - as follows:

void runScriptSeparateThread(TestScript script)
{
    // do some stuff

    Thread runScriptThread = new Thread(() => executeScript(script));
    runScriptThread.SetApartmentState(ApartmentState.STA);
    runScriptThread.Start();

    if (runScriptThread.Join(timeout) == false)
    {
        runScriptThread.Abort();
        File.AppendAllText(@"C:\log.txt", "Error: timeout ");
    }
    else
    {
        File.AppendAllText(@"C:\log.txt", "Message outer");
    }

    // do some other stuff
}

void executeScript(TestScript script)
{
    // run test script using reflection calls to external assemblies
    // includes invocation of new threads which will live after this thread finishes
    // can potentially include any calls - according to needs of test automation

    File.AppendAllText(@"C:\log.txt", "Message inner");
}

Problem is: Some times, after method executeScript() reaches its final line in its thread - method .Join() in the main thread continues to wait for timeout. That is - text "Message inner" is present in the "C:\log.txt" file, but text "Message outer" is missing.

NB: Behavior described above reproduces intermittently for cases when new threads with STA apartment state are spawned in the beginning of executeScript() method. New threads perform monitoring of UI controls with Ranorex tools - which perform behind the scene Win32 API calls that I am unfamiliar with. All of new threads' references are passed to the main thread and suppose to live after thread of executeScript() method exists.

Method executeScript makes calls with reflection according to automated script - and can potentially do any calls which can be implemented with .NET on a system.

My question is: Is it possible that invocation of new threads blocks execution of executeScript() method in separate thread - even after method reaches its last line? Can it be that STA apartment state of the thread and some Win32 calls that cause message pumping are the reason of hanging .Join() method for thread after thread's function passes all lines?

Note: Hang of .Join() method happens very rarely and was reproduced only on lab machines. I did not manage to reproduce behavior on local machine - even after automatic executing hundreds of times overnight.

Workaround found: So far I have ended up with following work around - resorted to usage of ManualResetEventSlim to wait for completion of the thread as below:

private ManualResetEventSlim executionControl = new ManualResetEventSlim();
private void runScriptSeparateThread(TestScript script)
{
    this.executionControl.Reset();

    Thread runScriptThread = new Thread(() => executeScript(script));
    runScriptThread.SetApartmentState(ApartmentState.STA);
    runScriptThread.Start();

    if (this.executionControl.Wait(timeout))
    {
        runScriptThread.Abort();
        File.AppendAllText(@"C:\log.txt", "Message outer");
    }
    else
    {
        File.AppendAllText(@"C:\log.txt", "Error: timeout ");
    }
}

void executeScript(TestScript script)
{
    // execute test automation

    File.AppendAllText(@"C:\log.txt", "Message inner");
    this.executionControl.Set();
}

Posted the same question on MSDN forum.

Andrii Kalytiiuk
  • 1,501
  • 14
  • 26
  • 1
    My gut tells me that it's either the disposal of an object or the logger. Have you tried calling Dispose on the IDisposable instances before the routine exits to see if any of those doesn't return? – Graymatter May 06 '14 at 07:52
  • @Graymatter Have not tried yet but I pass all the instances to the main thread - and want to use them later on in the main thread (after current thread exits). So non-disposed instances can be the reason of thread's hang? – Andrii Kalytiiuk May 06 '14 at 07:56
  • 1
    @AndriiKalytiiuk no, a non-disposed object can't do anything - however, if you are exiting a `using` statement, then the `Dispose()` method will be executed, and it is possible (but not very common) that *that* (meaning: the body of `Dispose()`) might do something that could cause a hang – Marc Gravell May 06 '14 at 08:07
  • @Graymatter I have identified that reason is not the logger - after replacing of logger calls with `File.AppendAllText()` behavior still reproduced. All disposable instances created in my code were disposed appropriately. May the reason of hanging be *STA* apartment state of the thread and message pumping caused by Win32 calls from 3rd party components that are invoked at the beginning of the thread? – Andrii Kalytiiuk May 13 '14 at 10:56
  • Is runScriptSeparateThread called from UI thread? – m0s May 13 '14 at 11:07
  • @MarcGravell I have identified so far that neither `logger` nor disposal of some object are the reason of hanging `.Join()` method. Instead I have noticed that hanged thread has apartment state *STA* as well as threads spawned by it. All the threads perform calls of 3rd party ([Ranorex](http://www.ranorex.com)) components which make various *Win32 API* calls. Can it be that message pumping caused by 3rd party components calls - is the reason of `.Join()` method hanging after thread passed all lines? (I have updated text of my question with nearly the same message) – Andrii Kalytiiuk May 13 '14 at 11:08
  • @m0s No - it is called from the main thread of command line application. Main thread has `[STAThread]` attribute specified on `Main()` method - *STA* apartment state. – Andrii Kalytiiuk May 13 '14 at 11:09
  • @m0s While `runScriptSeparateThread` is not called from UI thread - thread of `executeScript()` method and some threads spawned by it have apartment state *STA* and make calls to [Ranorex](http://www.ranorex.com/) API that interacts with UI - and so may have same behavioral resemblance with UI threads. – Andrii Kalytiiuk May 13 '14 at 11:50
  • 1
    Are multiple Ranorex threads interacting with the ui at any given time? What may be happening is the ranorex threads are interacting with each other, and causing locks and timeouts within their scripts causing the behavior you are describing. – theDarse May 28 '14 at 18:42
  • @theDarse Really - multiple Ranorex threads interact with UI simultaneously. To make it simple - one thread is performing script, other threads (that can be of unlimited number) are continuously looking for dialogs that can randomly pop-up - to close those dialogs (in order to prevent automation script from first thread from blocking). – Andrii Kalytiiuk Jun 02 '14 at 10:16
  • Is it reproducable both on mono and ms .net (2.0 and 4.0 runtime)? – Vlad Nov 27 '14 at 22:35
  • @Vlad So far encountered described defect only with MS .NET 4.0 runtime. Do not know how it works with .NET 2.0 or Mono. – Andrii Kalytiiuk Nov 29 '14 at 17:50

1 Answers1

1

I had similar symptoms with application domain unload which blocked in some win 10 Machines. I observed with logs that when process exit logs display code after and app domain magically unloads.

My solution: isolate in dedicated process the actual ranorex job by sending in cmd line a file path of json object containing parameters needed for exec.

It looks ranorex is responsible for this mess. The fact it injects code in target process do not help...

Thierry Brémard
  • 625
  • 1
  • 5
  • 14