我在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_03()的线程之前创建“Method_01()”或“Method_02()”的线程,但是在“Method_03()”的线程开始之前没有保证结束。我的意思是“Method_01()”或“Method_02()”将丢失他们的CPU转向,“Method_03”将转为CPU并将完全结束。
在“Start()”方法中,我知道应该创建并运行“Method_01”和“Method_02()”的线程总数。问题是我正在寻找一种使用信号量或互斥量的方法来确保“Method_03()”的第一个语句将在运行“Method_01()”或“Method_02()”的所有线程结束后正好运行
答案 0 :(得分:3)
我想到的三个选项是:
Thread
个实例,并从Join
致电Method_03
所有实例。CountdownEvent
个实例,并从Wait
致电Method_03
。ManualResetEvent
或Method_01
电话分配一个Method_02
,并从WaitHandle.WaitAll
拨打Method_03
所有这些电话(这不是很可扩展)。< / LI>
我更喜欢使用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.
}
}
答案 1 :(得分:2)
Tasks
这似乎是一个完美的工作。下面我假设允许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();
答案 2 :(得分:1)
为什么不使用静态变量static volatile int threadRuns
,它将使用数字线程Method_01进行初始化,并运行Method_02。
然后在退出之前修改这两个方法中的每一个以递减threadRuns
:
...
lock(typeof(MyClass)) {
--threadRuns;
}
...
然后在Method_03的开头,等到threadRun为0,然后继续:
while(threadRuns != 0)
Thread.Sleep(10);
我是否正确理解了这个问题?
答案 3 :(得分:1)
你需要做的是为Method_01和Method_02中的每一个创建一个ManualResetEvent(初始化为unset)或其他一些WatHandle,然后让Method_03的线程在句柄集上使用WaitHandle.WaitAll。 / p>
或者,如果你可以引用用于运行Method_01和Method_02的Thread变量,你可以让Method_03的线程使用Thread.Join来等待它们。然而,这假设这些线程在完成Method_01和Method_02的执行时实际终止 - 如果不是,则需要求助于我提到的第一个解决方案。
答案 4 :(得分:1)
在Barrier类中实际上有一个替代品是.Net 4.0中的新选项。这简化了跨多个线程进行信令传递的方式。
您可以执行类似以下代码的操作,但这在同步不同的处理线程时非常有用。
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.
}
}