【问题标题】:How to make threads go through a gate in order using C#如何使用 C# 使线程按顺序通过门
【发布时间】:2015-02-11 11:35:48
【问题描述】:

我有三个线程,部分代码可以并行运行,有些部分被锁定(当时只有一个线程)。然而,一把锁只需要让它们按顺序进入即可。由于这是一个循环,它变得更加复杂。我该如何做出这种行为?

如果我有一个打印语句,我希望收到以下输出: 1,2,3,1,2,3,1,2,3.... 目前我收到 2,3,1,3,1,3,2,1,2 A.K.A.随机顺序。

三个线程并行执行的代码:

while (true){                   
    lock (fetchLock){
        if(done){
            break;
        }
        //Do stuff one at the time
    }
    //Do stuff in parralell
    lock (displayLock){
    //Do stuff one at the time but need's to be in order.
    }
}

【问题讨论】:

  • 请出示您的代码

标签: c# multithreading locking


【解决方案1】:

您可以结合使用BarrierAutoResetEvent 来实现此目的。

首先,您使用Barrier.SignalAndWait() 确保所有线程在继续之前达到一个共同点。这个共同点是您希望线程按顺序执行某些代码的点。

然后你使用numberOfThreads-1AutoResetEvents 来同步线程。第一个线程不需要等待任何其他线程,但在它完成后应该发出下一个线程正在等待的事件。

中间线程(如果线程总数超过 3 个,则为线程)需要等待前一个线程发出通知它继续的事件。完成后,中间线程应该发出下一个线程正在等待的事件。

最后一个线程需要等待前一个线程发出通知它继续的事件。由于它是最后一个线程,它不需要发出事件信号来告诉下一个线程继续。

最后,您将线程与另一个对 Barrier.SignalAndWait() 的调用重新同步。

这是通过示例控制台应用程序最容易显示的。如果你运行它,你会看到线程应该按顺序完成的工作(输出中以字母“B”为前缀)确实总是按顺序完成,而其他工作(以字母“A”为前缀") 以随机顺序执行。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    public static class Program
    {
        public static void Main()
        {
            using (Barrier barrier = new Barrier(3))
            using (AutoResetEvent t2 = new AutoResetEvent(false))
            using (AutoResetEvent t3 = new AutoResetEvent(false))
            {
                Parallel.Invoke
                (
                    () => worker(1, barrier, null, t2),
                    () => worker(2, barrier, t2, t3),
                    () => worker(3, barrier, t3, null)
                );
            }
        }

        private static void worker(int threadId, Barrier barrier, AutoResetEvent thisThreadEvent, AutoResetEvent nextThreadEvent)
        {
            Random rng = new Random(threadId);

            for (int i = 0; i < 1000; ++i)
            {
                doSomething(threadId, rng); // We don't care what order threads execute this code.

                barrier.SignalAndWait(); // Wait for all threads to reach this point.

                if (thisThreadEvent != null)   // If this thread is supposed to wait for a signal
                    thisThreadEvent.WaitOne(); // before proceeding, then wait for it.

                doWorkThatMustBeDoneInThreadOrder(threadId);

                if (nextThreadEvent != null) // If this thread is supposed to raise a signal to indicate
                    nextThreadEvent.Set();   // that the next thread should proceed, then raise it.

                barrier.SignalAndWait(); // Wait for all threads to reach this point.
            }
        }

        private static void doWorkThatMustBeDoneInThreadOrder(int threadId)
        {
            Console.WriteLine("   B" + threadId);
            Thread.Sleep(200); // Simulate work.
        }

        private static void doSomething(int threadId, Random rng)
        {
            for (int i = 0; i < 5; ++i)
            {
                Thread.Sleep(rng.Next(50)); // Simulate indeterminate amount of work.
                Console.WriteLine("A" + threadId);
            }
        }
    }
}

【讨论】:

  • 这正是我想要的。非常感谢!
猜你喜欢
  • 2015-06-08
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多