5

我有这个简单的代码:

public void Run()
{
   var invokerThread = new Thread(new ThreadStart(RunOnBackground));
   invokerThread.Start();
}

private void RunOnBackground()
{
   Trace.WriteLine("hi");
   ...
}

不幸的是,当运行此代码(来自第三方进程)时,线程并没有真正运行。在进程资源管理器和 VS 调试器中,我看到线程已创建并且其状态为“正在运行”。

主线程的单元是 STA,我在内部线程上尝试了 STA 和 MTA。

当我最后添加到Run()方法时,invokerThread.Join();线程确实运行。但话又说回来,它并没有真正帮助。

我错过了什么?

编辑:这是有关代码托管的更多信息-

Run()方法是通过 COM 互操作从一个也是托管可执行程序集的进程调用的(使用 COM 互操作的原因是因为系统中的所有其他组件都是本机的)。

该方法RunOnBackground()在跟踪之后包含更多代码,通常其执行持续 10 到 20 秒,包括启动另一个进程并等待其终止。此外,我在代码中还有一些其他区域,我将一些调试信息写入 Trace。在调试代码时,Run()照常运行,并且在invokerThread.Start();调用者线程的状态为“正在运行”之后(尽管RunOnBackground()方法内的断点不会停止)。

当我在方法invokerThread.Join()的末尾添加时,调试Run()器会RunOnBackground() Join().

4

2 回答 2

3

关于 RunOnBackground() 的真正作用,缺少一些关键信息。这与在工作线程上使用单元线程 COM 对象时发生的情况非常匹配。COM 自动将此类对象上的任何方法调用从工作线程编组到创建它的 STA 线程。

这只有在 STA 线程遵守 STA 线程要求时才能正常工作。它必须泵出一个消息循环并且不能阻塞。打破这些规则很可能会导致死锁,直到 STA 线程调度封送调用,工作线程调用才能完成。看到 Thread.Join() 解决问题的一个明确迹象表明这是正在发生的事情。当在 STA 线程上调用它时,它会在 CLR 内部抽出一个消息循环。

要诊断这一点,您需要 Debug + Windows + Threads 来查看该工作线程正在阻塞什么。如果我的猜测是正确的,它将被深埋在 COM 管道代码中,等待编组调用完成。您只能通过启用非托管代码调试和设置 Microsoft 符号服务器来查看这一点,以便您获得管道代码的调试符号并获得可靠的堆栈跟踪。

解决这个问题会很困难。当它明确声明它不支持多线程时,你不能神奇地翻转开关并使代码在线程上运行。您必须在调用其方法的同一线程上创建 COM 对象的实例。并且该线程必须是 STA 线程。检查此示例代码以了解该方法。如果您不控制 COM 对象的创建,那么您将陷入困境。

于 2010-12-13T15:45:37.787 回答
0

我可能会说些愚蠢的话,但这是我在MSDN Threads中看到的。

查看最后的示例部分。

该示例的输出很有趣,您可以看到创建和启动的线程仅在主线程执行 Sleep(0) 或 Thread.Join() 时才开始执行。

这似乎是发生在你身上的事情,不是吗?

也许尝试在您的主线程上使用 Sleep(0) 来真正启动您的工作线程。

另一种解决方法是使用BackGroundWorker

顾名思义,它适用于背景并且非常易于使用。它可能对你很有用。

于 2010-12-13T00:17:10.930 回答