如何确保一个线程恰好在特定数量的其他线程运行结束后运行?
我在 C# 中有一个这样的类:
public MyClass
{
public void Start() { ... }
public void Method_01() { ... }
public void Method_02() { ... }
public void Method_03() { ... }
}
当我调用“Start()”方法时,外部类开始工作,并将创建许多并行线程,这些并行线程调用“Method_01()”和“Method_02()”形式以上类。外部类工作结束后,“Method_03()”将在另一个并行线程中运行。
“Method_01()”或“Method_02()”线程在创建 Method_03() 线程之前创建,但不保证在“Method_03()”线程启动之前结束。我的意思是“Method_01()”或“Method_02()”将失去其CPU 轮次,而“Method_03”将获得CPU 轮次并将完全结束。
在“Start()”方法中,我知道应该创建和运行“Method_01”和“Method_02()”的线程总数。问题是我正在寻找一种使用信号量或互斥体的方法,以确保“Method_03()”的第一个语句将在运行“Method_01()”或“Method_02()”的所有线程结束后运行。
I have a class in C# like this:
public MyClass
{
public void Start() { ... }
public void Method_01() { ... }
public void Method_02() { ... }
public void Method_03() { ... }
}
When I call the "Start()" method, an external class start to work and will create many parallel threads that those parallel threads call the "Method_01()" and "Method_02()" form above class. after end of working of the external class, the "Method_03()" will be run in another parallel thread.
Threads of "Method_01()" or "Method_02()" are created before creation of thread of Method_03(), but there is no guaranty to end before start of thread of "Method_03()". I mean the "Method_01()" or the "Method_02()" will lost their CPU turn and the "Method_03" will get the CPU turn and will end completely.
In the "Start()" method I know the total number of threads that are supposed to create and run "Method_01" and "Method_02()". The question is that I'm searching for a way using semaphore or mutex to ensure that the first statement of "Method_03()" will be run exactly after end of all threads which are running "Method_01()" or "Method_02()".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我想到的三个选项是:
Thread
实例数组,并从Method_03
对所有实例调用Join
。CountdownEvent
实例并从Method_03
调用Wait
。Method_01
或Method_02
调用分配一个ManualResetEvent
,并对来自的所有调用调用
(这不太可扩展)。WaitHandle.WaitAll
Method_03我更喜欢使用 CountdownEvent ,因为它的用途更加广泛,并且仍然具有超强的可扩展性。
Three options that come to mind are:
Thread
instances and callJoin
on all of them fromMethod_03
.CountdownEvent
instance and callWait
fromMethod_03
.ManualResetEvent
for eachMethod_01
orMethod_02
call and callWaitHandle.WaitAll
on all of them fromMethod_03
(this is not very scalable).I prefer to use a
CountdownEvent
because it is a lot more versatile and is still super scalable.这对于
Tasks
来说似乎是一项完美的工作。下面我假设允许Method01
和Method02
并发运行,没有特定的调用或完成顺序(没有保证,只是在没有测试的情况下输入内存不足):This appears to be a perfect job for
Tasks
. Below I assume thatMethod01
andMethod02
are allowed to run concurrently with no specific order of invocation or finishing (with no guarantee, just typed in out of memory without testing):听起来您需要做的是为 Method_01 和 Method_02 创建一个 ManualResetEvent (初始化为取消设置)或其他一些 WatHandle,然后让 Method_03 的线程使用 WaitHandle.WaitAll 上的集合手柄。
或者,如果您可以引用用于运行 Method_01 和 Method_02 的线程变量,则可以让 Method_03 的线程使用 Thread.Join 来等待这两个线程。然而,这假设这些线程在完成 Method_01 和 Method_02 的执行时实际上已终止 - 如果它们没有完成,则需要诉诸我提到的第一个解决方案。
What it sounds like you need to do is to create a ManualResetEvent (initialized to unset) or some other WatHandle for each of Method_01 and Method_02, and then have Method_03's thread use WaitHandle.WaitAll on the set of handles.
Alternatively, if you can reference the Thread variables used to run Method_01 and Method_02, you could have Method_03's thread use Thread.Join to wait on both. This assumes however that those threads are actually terminated when they complete execution of Method_01 and Method_02- if they are not, you need to resort to the first solution I mention.
为什么不使用静态变量
static volatile int threadRuns
,它用将运行的线程数Method_01和Method_02进行初始化。然后,您修改这两个方法中的每一个,以在退出之前递减
threadRuns
:然后在 Method_03 的开头,您等到 threadRuns 为 0,然后继续:
我是否正确理解了问题?
Why not use a static variable
static volatile int threadRuns
, which is initialized with the number threads Method_01 and Method_02 will be run.Then you modify each of those two methods to decrement
threadRuns
just before exit:Then in the beginning of Method_03 you wait until threadRuns is 0 and then proceed:
Did I understand the quesiton correctly?
事实上,Barrier 类中有一个替代方案,它是 .Net 4.0 中新增的。这简化了跨多个线程发送信号的方式。
您可以执行类似以下代码的操作,但这在同步不同处理线程时最有用。
我还想建议,由于您的问题陈述非常抽象,因此通常使用 countdownevent 解决的实际问题现在可以使用新的 Parallel 或 PLINQ 功能更好地解决。如果您实际上在代码中处理集合或某些内容,则可能会出现如下所示的内容。
There is actually an alternative in the Barrier class that is new in .Net 4.0. This simplifies the how you can do the signalling across multiple threads.
You could do something like the following code, but this is mostly useful when synchronizing different processing threads.
I would also like to suggest that since your problem statement was quite abstract, that often actual problems that are solved using countdownevent are now better solved using the new Parallel or PLINQ capabilities. If you were actually processing a collection or something in your code, you might have something like the following.