同步线程协程 [英] Synchronised threads coroutines

查看:84
本文介绍了同步线程协程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试让线程在彼此之前先等待,以便它们保持同步.

I'm trying to get threads to wait for each other before preceding so they stay in sync.

在我的实际程序中,我有很多IObjectObserved对象(在其自己的线程上)发送事件,并且我想使所有内容保持同步,以便IObjectListener(在其自己的线程上)可以侦听这些对象之一50次,然后及时订阅另一个以捕获其第51个事件.

In my actual program I have lots of IObjectObserved objects (on their own threads) sending out events and I want to keep everything in sync so an IObjectListener (on its own thread) can listen to one of these objects 50 times and then subscribe to another in time to catch its 51st event.

我还没走那么远,但是我认为同步线程是主要问题.我设法使用AutoResetEvent的两种方式来实现此目的.有没有更好的方法可以做到这一点?

I haven't got that far yet, but I think synchronizing threads is the main problem. I'm managed to achieve this with two way signalling using AutoResetEvents. Is there not a better way to do this?

class Program
{
    static EventWaitHandle _ready = new AutoResetEvent(true);
    static EventWaitHandle _go = new AutoResetEvent(false);
    static EventWaitHandle _ready1 = new AutoResetEvent(true);
    static EventWaitHandle _go1 = new AutoResetEvent(false);
    static EventWaitHandle _ready2 = new AutoResetEvent(true);
    static EventWaitHandle _go2 = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        new Thread(Waiter).Start();
        new Thread(Waiter1).Start();
        new Thread(Waiter2).Start();
        for (; ; )
        {
            _ready.WaitOne();
            _ready1.WaitOne();
            _ready2.WaitOne();
            Console.WriteLine("new round");
            _go.Set();
            _go1.Set();
            _go2.Set();
        }
    }

    static void Waiter()
    {
        for (; ; )
        {
            _go.WaitOne();
            Thread.Sleep(1000);
            Console.WriteLine("Waiter run");
            _ready.Set();
        }
    }
    static void Waiter1()
    {
        for (; ; )
        {
            _go1.WaitOne();
            Thread.Sleep(5000);
            Console.WriteLine("water1 run");
            _ready1.Set();
        }
    }
    static void Waiter2()
    {
        for (; ; )
        {
            _go2.WaitOne();
            Thread.Sleep(500);
            Console.WriteLine("water2 run");
            _ready2.Set();
        }
    }
}

推荐答案

您可以简化一些事情.

  • 您可以使用一个CountdownEvent来代替等待发送3个句柄的信号. cde.Wait将一直阻塞,直到发出3次信号为止.
  • 您也可以使用SemaphoreSlim释放多个线程,而不是使用3个不同的句柄. sem.Release(3)最多可以取消阻止在sem.Wait()上被阻止的3个线程.
  • You could use one CountdownEvent instead of waiting for 3 handles to be signaled. cde.Wait will block until it has been signaled 3 times.
  • You could also use a SemaphoreSlim to release multiple threads, instead of using 3 different handles. sem.Release(3) will unblock up to 3 threads blocked on sem.Wait().


static CountdownEvent cde = new CountdownEvent(3);
static SemaphoreSlim sem = new SemaphoreSlim(3);

static void X()
{
    new Thread(Waiter).Start();
    new Thread(Waiter).Start();
    new Thread(Waiter).Start();
    for (; ; )
    {
        cde.Wait();
        Debug.WriteLine("new round");

        cde.Reset(3);
        sem.Release(3);
    }
}

static void Waiter()
{
    for (; ; )
    {
        sem.Wait();
        Thread.Sleep(1000);
        Debug.WriteLine("Waiter run");
        cde.Signal();
    }
}

请注意,现在所有线程都可以重用相同的代码.

Note that now all threads can reuse the same code.

修改:

如评论中所述,一个线程可能会窃取另一线程的回合. 如果您不希望发生这种情况,请 Barrier 将完成这项工作:

As stated in the comments, one thread might steal another thread's round. If you don't want this to happen, a Barrier will do the job:

   private static Barrier _barrier;

   private static void SynchronizeThreeThreads()
   {
       _barrier = new Barrier(3, b =>
                                Debug.WriteLine("new round"));

       new Thread(Waiter).Start();
       new Thread(Waiter).Start();
       new Thread(Waiter).Start();

       //let the threads run for 5s
       Thread.Sleep(5000);
   }
   static void Waiter()
   {
       while(true)
       {
           Debug.WriteLine("Thread {0} done.", Thread.CurrentThread.ManagedThreadId);
           _barrier.SignalAndWait();
       }
   }

您将3位参与者添加到障碍中.到达障碍(即执行_barrier.SignalAndWait())的第一和第二参与者将一直阻塞,直到其余参与者也到达障碍为止.当所有参与者都达到障碍时,他们将全部被释放并进行下一轮比赛.

You add 3 participants to the barrier. The first and second participants to reach the barrier (i.e., to execute _barrier.SignalAndWait()) will block until the remaining participants reaches it too. When all participants have reached the barrier, they will all be released and go for another round.

请注意,我将lambda传递给了屏障构造函数-这是后期阶段操作",该操作将在所有参与者到达屏障后 before 释放它们.

Notice that I passed a lambda to the barrier constructor - that's the "post-phase action", an action that will be executed after all participants have reached the barrier, and before releasing them.

这篇关于同步线程协程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆