我有用于执行测试自动化的控制台 .NET 应用程序。
应用程序从主线程调用一个单独的线程,并在该新线程中执行自动化脚本 - 如下:
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"
缺少文本。
注意:当在方法开始时产生具有STA单元状态的新线程时,上述行为会间歇性地重现executeScript()
。新线程使用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 论坛上发布了相同的问题。