简体   繁体   English

等待任何线程完成,而不是全部

[英]Wait for ANY thread to finish, not ALL

I'm starting multiple threads and would like to know when any of then finishes. 我开始多线程和想知道当任何然后完成。 I know the following code: 我知道以下代码:

foreach (Thread t in threads)
    t.Join();

But it will only wait for all threads together. 但它只会等待所有线程在一起。 That's much too late. 那太晚了。 I need to know when one thread finishes, even when other threads are still running. 我需要知道一个线程何时完成,即使其他线程仍在运行。 I'm looking for something equivalent to WaitAny only for threads. 我正在为线程寻找等同于WaitAny东西。 But I can't add code to all threads I'm monitoring, so using signals or other synchronisation objects is not an option. 但是我无法将代码添加到我正在监视的所有线程中,因此使用信号或其他同步对象不是一种选择。

Some clarification: I'm working on a logging/tracing tool that should log the application's activity. 一些澄清:我正在开发一个记录/跟踪工具,它应该记录应用程序的活动。 I can insert log statements when a thread starts, but I can't insert a log statement on every possible way out of the thread (multiple exit points, exceptions etc.). 我可以在线程启动时插入日志语句,但是我不能在线程的每个可能的方式上插入日志语句(多个退出点,异常等)。 So I'd like to register the new thread and then be notified when it finishes to write a log entry. 所以我想注册新线程,然后在完成写入日志条目时收到通知。 I could asynchronously Join on every thread, but that means a second thread for every monitored thread which may seem a bit much overhead. 我可以异步Join每个线程,但这意味着每个受监控线程的第二个线程可能看起来有点开销。 Threads are used by various means, be it a BackgroundWorker , Task or pool thread. 线程通过各种方式使用,无论是BackgroundWorkerTask还是池线程。 In its essence, it's a thread and I'd like to know when it's done. 从本质上讲,它是一个线程,我想知道它什么时候完成。 The exact thread mechanism is defined by the application, not the logging solution. 确切的线程机制由应用程序定义,而不是日志记录解决方案。

Instead of Threads use Tasks . 而不是线程使用任务 It has the method WaitAny . 它有WaitAny方法。

Task.WaitAny

As you can read here , 你可以在这里看到

  • More efficient and more scalable use of system resources. 更高效,更可扩展的系统资源使用。
  • More programmatic control than is possible with a thread or work item. 比线程或工作项更多的程序控制。

In my opinion WaitHandle.WaitAny is the best solution, since you don't like to use it for some xyz reason you can try something like this. 在我看来WaitHandle.WaitAny是最好的解决方案,因为你不喜欢用它来解决一些xyz的原因,你可以试试这样的东西。

Take the advantage of Thread.Join(int) method which takes millisecond timeout and returns true when thread is terminated or false when timed out. 利用Thread.Join(int)方法,该方法占用millisecond timeout并在线程终止时返回true ,或在超时时返回false

List<Thread> threads = new List<Thread>();

while (!threads.Any(x=> x.Join(100)))
{

}

You can alter the timeout of Join If you know how long it will take. 您可以更改Join的超时如果您知道需要多长时间。

My answer is based on your clarification that all you have is Thread.Current . 我的回答是基于你的澄清,你所拥有的只是Thread.Current Disclaimer: IMO, what you're trying to do is a hack, thus my idea by all means is a hack too . 免责声明:IMO,你要做的就是黑客,所以我的想法无论如何都是黑客攻击

So, use reflection to obtain the set of native Win32 handles for your desired threads. 因此,使用反射来获取所需线程的本机Win32句柄集。 Your are looking for Thread.GetNativeHandle method which is internal , so you call it like thread.GetType().InvokeMember("GetNativeHandle", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, ...) . 您正在寻找internal Thread.GetNativeHandle方法,因此您可以将其thread.GetType().InvokeMember("GetNativeHandle", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, ...) Use a reflection tool of your choice or Framework sources to learn more about it. 使用您选择的反射工具或框架源来了解有关它的更多信息。 Once you've got the handles, go on with one of the following options: 获得句柄后,继续使用以下选项之一:

  • Set up your own implementation of SynchronizationContext (derive from it) and use SynchronizationContext.WaitHelper(waitAll: false) to wait for your unmanaged handles. 设置自己的SynchronizationContext实现(从中派生)并使用SynchronizationContext.WaitHelper(waitAll:false)等待非托管句柄。

  • Use the raw Win32 API like WaitForMultipleObjects or CoWaitForMultipleObjects (depending on whether you need to pump messages). 使用原始Win32 API,如WaitForMultipleObjectsCoWaitForMultipleObjects (取决于您是否需要抽取消息)。

Perform the wait on a separate child or pool thread. 在单独的子线程或池线程上执行等待。

[EDITED] Depending on the execution environment of your target threads, this hack may not work, because one-to-one mapping between managed and unmanaged threads is not guaranteed : [已编辑]根据目标线程的执行环境,此hack可能无法正常工作,因为无法保证托管和非托管线程之间的一对一映射:

It is possible to determine the Windows thread that is executing the code for a managed thread and to retrieve its handle. 可以确定正在执行托管线程代码的Windows线程并检索其句柄。 However, it still doesn't make sense to call the SetThreadAffinityMask function for this Windows thread, because the managed scheduler can continue the execution of a managed thread in another Windows thread . 但是,为此Windows线程调用SetThreadAffinityMask函数仍然没有意义, 因为托管调度程序可以继续在另一个Windows线程中执行托管线程

It appears however, this may be an implication only for custom CLR hosts. 但是,这似乎只对自定义CLR主机有影响 Also, it appears to be possible to control managed thread affinity with Thread.BeginThreadAffinity and Thread.EndThreadAffinity . 此外,似乎可以使用Thread.BeginThreadAffinityThread.EndThreadAffinity 控制托管线程关联

You could use a background worker for your working threads. 您可以使用后台工作程序来处理工作线程。

Then hook all the RunWorkerCompleted events to a method that will wait for them. 然后将所有RunWorkerCompleted事件挂钩到将等待它们的方法。

If you want that to be synched to the code where you're currently waiting for the join, then the problem is reduced to just synchronizing that single event method to that place in code. 如果您希望将其同步到当前正在等待连接的代码,则问题将减少为仅将该单个事件方法同步到代码中的该位置。

Better yet, I'd suggest to do what you're doing asynchronously without blocking, and just do what you want in the event. 更好的是,我建议你在不阻塞的情况下异步进行你正在做的事情,并在事件中做你想做的事。

Would you consider wrapping your thread invocations with another 'logging' thread? 你会考虑用另一个“日志记录”线程包装你的线程调用吗? That way you could log synchronously before & after the thread run. 这样你就可以在线程运行之前和之后同步记录。

Something like this pseudo-code: 像这样的伪代码:

int threadLogger(<parms>) {
    log("starting thread");
    retcode = ActualThreadBody(<parms>);
    log("exiting thread");
    return retcode;
}

If you have more information on the thread started, you could log that as well. 如果您有关于已启动线程的更多信息,您也可以记录该信息。 You could also take the thread function as a parameter in the case where you have multiple types of threads to start, which it sounds like you do. 在有多种类型的线程可以启动的情况下,您也可以将线程函数作为参数,这听起来就像您一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM