C# 如何确保一个线程在特定数量的其他线程运行结束后运行?
我有一门C#课,像这样:C# 如何确保一个线程在特定数量的其他线程运行结束后运行?,c#,multithreading,synchronization,semaphore,C#,Multithreading,Synchronization,Semaphore,我有一门C#课,像这样: public MyClass { public void Start() { ... } public void Method_01() { ... } public void Method_02() { ... } public void Method_03() { ... } } 当我调用“Start()”方法时,一个外部类开始工作,并将创建许多并行线程,这些并行线程称为类上方的“method_01()”和“method_02()”形式。
public MyClass
{
public void Start() { ... }
public void Method_01() { ... }
public void Method_02() { ... }
public void Method_03() { ... }
}
当我调用“Start()”方法时,一个外部类开始工作,并将创建许多并行线程,这些并行线程称为类上方的“method_01()”和“method_02()”形式。外部类工作结束后,“方法_03()”将在另一个并行线程中运行
“Method_01()”或“Method_02()”的线程是在创建方法_03()的线程之前创建的,但不能保证在“Method_03()的线程开始之前结束。我的意思是“Method_01()”或“Method_02()”将失去它们的CPU周期,“Method_03”将获得CPU周期,并将完全结束
在“Start()”方法中,我知道应该创建和运行“method_01”和“method_02()”的线程总数。问题是,我正在寻找一种使用信号量或互斥量的方法,以确保“Method_03()”的第一条语句将恰好在运行“Method_01()”或“Method_02()”的所有线程结束后运行,使用线程数初始化,将运行方法\u 01和方法\u 02。 然后,在退出之前,修改这两种方法中的每一种,以减少
threadRuns
:
...
lock(typeof(MyClass)) {
--threadRuns;
}
...
然后在方法_03的开头,等待threadRuns为0,然后继续:
while(threadRuns != 0)
Thread.Sleep(10);
我是否正确理解了这个问题?听起来您需要做的是为方法\u 01和方法\u 02中的每一个创建一个ManualResetEvent(初始化为unset)或一些其他WatHandle,然后在句柄集上使用方法\u 03的线程
或者,如果可以引用用于运行方法\u 01和方法\u 02的线程变量,则可以让方法\u 03的线程使用Thread.Join来等待这两个线程。但是,这假设这些线程在完成方法_01和方法_02的执行时实际终止-如果它们没有终止,则需要使用我提到的第一个解决方案。想到的三个选项是:
- 保留一个
实例数组,并从线程
对所有实例调用方法\u 03
Join
- 使用单个
实例并从CountdownEvent
调用Method\u 03
Wait
- 为每个
或Method\u 01
调用和调用Method\u 02
分配一个WaitHandle.WaitAll
(这不是很好扩展)ManualResetEvent
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.
}
}
公共类MyClass
{
私有倒计时事件m_Finished=新倒计时事件(0);
公开作废开始()
{
m_Finished.AddCount();//递增以指示此线程处于活动状态。
for(int i=0;i<线程数;i++)
{
m_Finished.AddCount();//递增以指示另一个活动线程。
新线程(方法_01).Start();
}
for(int i=0;i<线程数;i++)
{
m_Finished.AddCount();//递增以指示另一个活动线程。
新线程(方法_02).Start();
}
新线程(方法_03).Start();
m_Finished.Signal();//表示此线程已完成的信号。
}
私有无效方法_01()
{
尝试
{
//在这里添加您的逻辑。
}
最后
{
m_Finished.Signal();//表示此线程已完成的信号。
}
}
私有无效方法_02()
{
尝试
{
//在这里添加您的逻辑。
}
最后
{
m_Finished.Signal();//表示此线程已完成的信号。
}
}
私有无效方法_03()
{
m_Finished.Wait();//等待所有信号。
//在这里添加您的逻辑。
}
}
实际上,在.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.
}
}
公共级同步器
{
私人壁垒(私人壁垒),;
公共void开始(int numThreads)
{
_屏障=新屏障((numThreads*2)+1);
for(int i=0;i
我还想建议,由于您的问题陈述非常抽象,通常使用countdownevent解决的实际问题现在使用新的并行或PLINQ功能可以更好地解决。如果您在代码中实际处理一个集合或其他内容,您可能会遇到如下情况
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.
}
}
公共级同步器
{
公共作废开始(列表集合)
{
新线程(()=>Method3(集合));
}
公共无效方法1(someClass)
{
//做一些工作。
}
公共无效方法2(someClass)
{
//做一些其他的工作。
}
公共作废方法3(列表集合)
{
//在平行线程中对每个项目进行处理。
Parallel.ForEach(集合,x=>{Method1(x);Method2(x);});
//对整个集合做一些工作,比如排序或其他。
}
}
对于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();