我有控制台.NET应用程序,用于执行测试自动化。
Application从主线程调用一个单独的线程,并且新线程执行自动脚本 - 如下所示:
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");
}
问题是:有时,在方法executeScript()
到达其线程中的最后一行后,主线程中的方法.Join()
继续等待超时。也就是说 - 文件"Message inner"
出现在"C:\log.txt"
文件中,但文字"Message outer"
丢失了。
NB:上述行为会在executeScript()
方法开头生成具有 STA 公寓状态的新线程的情况下间歇性地重现。新线程使用Ranorex工具执行UI控件的监视 - 这些工具在我不熟悉的场景 Win32 API 调用之后执行。所有新线程的引用都传递给主线程,并假设存在executeScript()
方法的线程后生效。
方法executeScript
根据自动脚本进行反射调用 - 并且可以执行任何可以在系统上使用.NET实现的调用。
我的问题是:调用新线程是否有可能阻止在单独的线程中执行executeScript()
方法 - 即使在方法到达最后一行之后?可能是线程的 STA 单元状态以及引起消息抽取的一些Win32调用是线程函数通过所有行后挂起.Join()
方法的原因吗?
注意: .Join()
方法的挂起很少发生,只能在实验室机器上复制。我无法在本地计算机上重现行为 - 即使在一夜之间自动执行数百次之后也是如此。
找到了解决方法:到目前为止,我已经完成了下面的工作 - 使用ManualResetEventSlim
等待线程的完成,如下所示:
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();
}
在MSDN论坛上发布the same question。