这是我正在研究的通用代码。问题是如何停止2nd_thread直到所有sub_threads都被执行并且main_thread正在休眠。类似地,main_thread也将等待返回for循环执行。如果当前正在执行,则main_thread将等待2nd_thread执行。
我想过使用可由线程修改的全局变量来通知2nd_thread它是否应该开始执行。但是,多个线程可能会同时访问全局变量,从而导致问题。
我甚至想过用静态对象锁定sub_threads,main_thread和2nd_thread但如果我锁定了sub_threads那么就不再有sub_threads的多线程了。
如何解决这个问题?
void main()
{
//Do something here
Thread thread1 = new thread(main_thread);
thread1.start();
//Do something here
if(something) //Button event
{
Thread thread2 = new Thread(2nd_thread)
thread2.start();
}
}
void main_thread()
{
while(true)
{
//Do something
if(after something, if condition true)
{
new Thread(sub_thread).start();
}
//Do something
Thread.sleep(_sometime_);
}
}
void 2nd_thread()
{
//This thread must execute only if main_thread is sleeping
//and all sub_threads have been executed. Till then wait for
//other threads to execute.
}
void sub_thread()
{
//Do something
}
答案 0 :(得分:1)
我会使用AutoResetEvent,一个线程同步原语,在这些情况下非常有用。如果您预先知道子线程的数量,您可以创建这些等待句柄的列表并等待它们,包括主线程。一旦完成处理,第二个线程就可以发出主线程的信号。诚然不是最漂亮的,但我试过一个例子,例如:
private AutoResetEvent _mainThreadWaitHandle = new AutoResetEvent(false);
private AutoResetEvent _secondThreadWaitHandle = new AutoResetEvent(false);
private List<AutoResetEvent> _subThreadWaitHandles = new List<AutoResetEvent>();
void main()
{
//Do something here
for(int i = 0; i < numSubThreads; i++) // TODO: Need to know numSubThreads.
_subThreadWaitHandles.Add(new AutoResetEvent(false));
Thread thread1 = new thread(main_thread);
thread1.start();
//Do something here
if(something) //Button event
{
Thread thread2 = new Thread(2nd_thread)
thread2.start();
}
}
void main_thread()
{
while(true)
{
//Do something
if(after something, if condition true)
{
// TODO: Need to work out which sub thread you are on if you know the number of thee sub threads up front and assign resetIndex with
// that particular indexed sub thread...
int setIndex = i; // TODO: work out i.
new Thread(() => sub_thread(setIndex)).start();
}
//Do something
// signal second thread it can proceed - however second thread is probably still waiting on all sub threads....
_mainThreadWaitHandle.Set();
Thread.sleep(_sometime_);
// now wait for second thread to complete...
_secondThreadWaitHandle.WaitOne();
}
}
void 2nd_thread()
{
//This thread must execute only if main_thread is sleeping
//and all sub_threads have been executed. Till then wait for
//other threads to execute.
List<WaitHandle> allWaitHandles = new List<WaitHandle>(_subThreadWaitHandles);
allWaitHandles.Add(_mainThreadWaitHandle);
// Wait on all sub threads and the main thread.
WaitHandle.WaitAll(allWaitHandles.ToArray());
// do stuff
//now signal to inform main thread it can proceed.
_secondThreadWaitHandle.Set();
}
void sub_thread(int setIndex)
{
//Do something
//Now signal to inform this has completed.
_subThreadWaitHandles[setIndex].Set();
}
答案 1 :(得分:1)
您的实际问题是您需要异步代码而不是并发代码。你设法编写的是同步并发代码。
您的“主线程”实际上是一个UI线程。你永远不应该永远调用任何可以阻止你的UI线程的东西。保证Thread.Sleep
至少阻止x毫秒。
你真正想要做的是启动一个新线程,然后当它完成时,在主线程上调用一些更新。异步并发代码。
您通常会在WinForm上使用Control.Invoke(delegate)
或使用SynchronizationContext.Current.Post(delegate)
来执行此操作。它很难做到而且效率不高,但这是我们在2000年代知道如何做到这一点的唯一方式(JAVA中的穷人仍然这样做)。
现在是2014年。您想使用Asynchronous-SingleThreaded代码。在这里,您使用Task
封装了串行端口访问,并在内部有一个事件,无线信号通知您的串行端口有数据供您使用。然后使用WinForm消息泵来安排处理串行端口的工作,并使用单个线程将工作与更新UI交错。
答案 2 :(得分:0)
如果不考虑其他线程框架,你可以用CountDownEvent实现你想要的功能(你的问题实际上有很多细节缺失,但这可以给你一个良好的开端)。
声明共享的CountDownEvent。
假设main_thread产生的工作线程数是预先知道的,您可以使用此数字初始化事件。工人中的最后一行代码是递减(= Signal()
)计数器。
2nd_thread的第一行代码将是Wait()
的事件。因此,只有当其内部计数达到零(即所有工作线程都已完成)时,它才会恢复执行。
如果你事先不知道工人的数量,每个新工人都可以动态增加计数器,但是你需要处理各种竞争条件(比如第一个工人有机会之前第二个线程开始工作)增加计数器..)。