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