根据其他线程的当前编程计数器锁定线程

时间:2014-10-16 07:37:29

标签: c# multithreading winforms

这是我正在研究的通用代码。问题是如何停止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
}

3 个答案:

答案 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()的事件。因此,只有当其内部计数达到零(即所有工作线程都已完成)时,它才会恢复执行。

如果你事先不知道工人的数量,每个新工人都可以动态增加计数器,但是你需要处理各种竞争条件(比如第一个工人有机会之前第二个线程开始工作)增加计数器..)。