[英]Wait for ANY thread to finish, not ALL
我开始多线程和想知道当任何然后完成。 我知道以下代码:
foreach (Thread t in threads)
t.Join();
但它只会等待所有线程在一起。 那太晚了。 我需要知道一个线程何时完成,即使其他线程仍在运行。 我正在为线程寻找等同于WaitAny
东西。 但是我无法将代码添加到我正在监视的所有线程中,因此使用信号或其他同步对象不是一种选择。
一些澄清:我正在开发一个记录/跟踪工具,它应该记录应用程序的活动。 我可以在线程启动时插入日志语句,但是我不能在线程的每个可能的方式上插入日志语句(多个退出点,异常等)。 所以我想注册新线程,然后在完成写入日志条目时收到通知。 我可以异步Join
每个线程,但这意味着每个受监控线程的第二个线程可能看起来有点开销。 线程通过各种方式使用,无论是BackgroundWorker
, Task
还是池线程。 从本质上讲,它是一个线程,我想知道它什么时候完成。 确切的线程机制由应用程序定义,而不是日志记录解决方案。
在我看来WaitHandle.WaitAny
是最好的解决方案,因为你不喜欢用它来解决一些xyz的原因,你可以试试这样的东西。
利用Thread.Join(int)方法,该方法占用millisecond timeout
并在线程终止时返回true
,或在超时时返回false
。
List<Thread> threads = new List<Thread>();
while (!threads.Any(x=> x.Join(100)))
{
}
您可以更改Join
的超时如果您知道需要多长时间。
我的回答是基于你的澄清,你所拥有的只是Thread.Current
。 免责声明:IMO,你要做的就是黑客,所以我的想法无论如何都是黑客攻击 。
因此,使用反射来获取所需线程的本机Win32句柄集。 您正在寻找internal
Thread.GetNativeHandle
方法,因此您可以将其thread.GetType().InvokeMember("GetNativeHandle", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, ...)
。 使用您选择的反射工具或框架源来了解有关它的更多信息。 获得句柄后,继续使用以下选项之一:
设置自己的SynchronizationContext
实现(从中派生)并使用SynchronizationContext.WaitHelper(waitAll:false)等待非托管句柄。
使用原始Win32 API,如WaitForMultipleObjects
或CoWaitForMultipleObjects
(取决于您是否需要抽取消息)。
在单独的子线程或池线程上执行等待。
[已编辑]根据目标线程的执行环境,此hack可能无法正常工作,因为无法保证托管和非托管线程之间的一对一映射:
可以确定正在执行托管线程代码的Windows线程并检索其句柄。 但是,为此Windows线程调用SetThreadAffinityMask函数仍然没有意义, 因为托管调度程序可以继续在另一个Windows线程中执行托管线程 。
但是,这似乎只对自定义CLR主机有影响 。 此外,似乎可以使用Thread.BeginThreadAffinity
和Thread.EndThreadAffinity
控制托管线程关联 。
您可以使用后台工作程序来处理工作线程。
然后将所有RunWorkerCompleted事件挂钩到将等待它们的方法。
如果您希望将其同步到当前正在等待连接的代码,则问题将减少为仅将该单个事件方法同步到代码中的该位置。
更好的是,我建议你在不阻塞的情况下异步进行你正在做的事情,并在事件中做你想做的事。
你会考虑用另一个“日志记录”线程包装你的线程调用吗? 这样你就可以在线程运行之前和之后同步记录。
像这样的伪代码:
int threadLogger(<parms>) {
log("starting thread");
retcode = ActualThreadBody(<parms>);
log("exiting thread");
return retcode;
}
如果您有关于已启动线程的更多信息,您也可以记录该信息。 在有多种类型的线程可以启动的情况下,您也可以将线程函数作为参数,这听起来就像您一样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.