如何解决如何确保一定数量的其他线程运行结束后恰好运行线程?
| 我在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()\”。
解决方法
想到的三个选项是:
保留一个数组
Thread
实例,并从Method_03
对其调用Join
。
使用单个CountdownEvent
实例,然后从Method_03
调用Wait
。
为每个Method_01
或Method_02
呼叫分配一个ManualResetEvent
,然后从Method_03
对其全部调用WaitHandle.WaitAll
(这不是很容易扩展)。
我更喜欢使用CountdownEvent
,因为它具有更多的通用性并且仍然具有超强的可扩展性。
public class MyClass
{
private CountdownEvent m_Finished = new CountdownEvent(0);
public void Start()
{
m_Finished.AddCount(); // Increment to indicate that this thread is active.
for (int i = 0; i < NUMBER_OF_THREADS; i++)
{
m_Finished.AddCount(); // Increment to indicate another active thread.
new Thread(Method_01).Start();
}
for (int i = 0; i < NUMBER_OF_THREADS; i++)
{
m_Finished.AddCount(); // Increment to indicate another active thread.
new Thread(Method_02).Start();
}
new Thread(Method_03).Start();
m_Finished.Signal(); // Signal to indicate that this thread is done.
}
private void Method_01()
{
try
{
// Add your logic here.
}
finally
{
m_Finished.Signal(); // Signal to indicate that this thread is done.
}
}
private void Method_02()
{
try
{
// Add your logic here.
}
finally
{
m_Finished.Signal(); // Signal to indicate that this thread is done.
}
}
private void Method_03()
{
m_Finished.Wait(); // Wait for all signals.
// Add your logic here.
}
}
, 这对于ѭ14来说似乎是完美的工作。下面我假设允许Method01
和Method02
并发运行,而没有特定的调用或完成顺序(没有保证,只是在没有测试的情况下键入内存即可):
int cTaskNumber01 = 3,cTaskNumber02 = 5;
Task tMaster = new Task(() => {
for (int tI = 0; tI < cTaskNumber01; ++tI)
new Task(Method01,TaskCreationOptions.AttachedToParent).Start();
for (int tI = 0; tI < cTaskNumber02; ++tI)
new Task(Method02,TaskCreationOptions.AttachedToParent).Start();
});
// after master and its children are finished,Method03 is invoked
tMaster.ContinueWith(Method03);
// let it go...
tMaster.Start();
, 听起来您需要做的是为Method_01和Method_02中的每一个创建一个ManualResetEvent(初始化为未设置)或其他一些WatHandle,然后让Method_03的线程在该句柄集上使用WaitHandle.WaitAll。
另外,如果您可以引用用于运行Method_01和Method_02的Thread变量,则可以让Method_03 \的线程使用Thread.Join来等待两者。但是,这假定那些线程在它们完成Method_01和Method_02的执行时实际上已终止,否则,您需要诉诸我提到的第一个解决方案。
, 为什么不使用静态变量static volatile int threadRuns
,该变量将用数字线程Method_01和Method_02初始化。
然后,您可以修改这两种方法中的每一种,以在退出前将ѭ19减1:
...
lock(typeof(MyClass)) {
--threadRuns;
}
...
然后在Method_03的开头,您等待直到threadRuns为0,然后继续:
while(threadRuns != 0)
Thread.Sleep(10);
我是否正确理解了这个问题?
, 实际上,.Net 4.0中的Barrier类中有一个替代方法。这简化了如何在多个线程之间进行信令。
您可以执行类似以下代码的操作,但这在同步不同的处理线程时最有用。
public class Synchro
{
private Barrier _barrier;
public void Start(int numThreads)
{
_barrier = new Barrier((numThreads * 2)+1);
for (int i = 0; i < numThreads; i++)
{
new Thread(Method1).Start();
new Thread(Method2).Start();
}
new Thread(Method3).Start();
}
public void Method1()
{
//Do some work
_barrier.SignalAndWait();
}
public void Method2()
{
//Do some other work.
_barrier.SignalAndWait();
}
public void Method3()
{
_barrier.SignalAndWait();
//Do some other cleanup work.
}
}
我还想建议您,因为您的问题陈述非常抽象,所以现在通常可以使用新的Parallel或PLINQ功能更好地解决使用countdownevent解决的实际问题。如果您实际上在处理集合或代码中的某些内容,则可能会有类似以下内容的内容。
public class Synchro
{
public void Start(List<someClass> collection)
{
new Thread(()=>Method3(collection));
}
public void Method1(someClass)
{
//Do some work.
}
public void Method2(someClass)
{
//Do some other work.
}
public void Method3(List<someClass> collection)
{
//Do your work on each item in Parrallel threads.
Parallel.ForEach(collection,x => { Method1(x); Method2(x); });
//Do some work on the total collection like sorting or whatever.
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。