如何使用C#使线程按顺序通过门 [英] How to make threads go through a gate in order using C#

查看:197
本文介绍了如何使用C#使线程按顺序通过门的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三个线程,部分代码可以并行运行,某些部分被锁定(当时只有一个线程).但是,一把锁只需要按顺序放开它们即可.由于这是一个循环,因此变得更加复杂.我该如何做?

I have three threads and some part of the code can run in parallel, some parts are locked(only one thread at the time). However one lock needs to only let them in in order. Since this is a loop it gets more complex. How do I make this behavior?

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

If i had a print statement I would like to receive the following output: 1,2,3,1,2,3,1,2,3.... currently I receive 2,3,1,3,1,3,2,1,2 A.K.A. random order.

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

The code which is executed in three threads in parallel:

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.
    }
}

推荐答案

您可以结合使用 AutoResetEvent 即可实现.

You could use a combination of Barrier and AutoResetEvent to achieve this.

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

Firstly, you use Barrier.SignalAndWait() to ensure that all the threads reach a common point before proceeding. This common point is the point at which you want the threads to execute some code in order.

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

Then you use numberOfThreads-1 AutoResetEvents to synchronise the threads. The first thread doesn't need to wait for any other thread, but after it has finished it should signal the event that the next thread is waiting on.

中间线程(或多个线程,如果总数超过3个线程)需要等待前一个线程发出信号,通知该事件继续进行.完成后,中间线程应发出信号通知下一个线程正在等待.

The middle thread (or threads if more than 3 threads total) needs to wait for the previous thread to signal the event that tells it to proceed. After it has finished, the middle thread should signal the event that the next thread is waiting on.

最后一个线程需要等待上一个线程发出信号,告知该事件继续进行.由于它是最后一个线程,因此不需要发信号通知下一个线程继续进行.

The last thread needs to wait for the previous thread to signal the event that tells it to proceed. Since it is the last thread, it does not need to signal an event to tell the next thread to proceed.

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

Finally, you resync the threads with another call to Barrier.SignalAndWait().

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

This is easiest to show via a sample console app. If you run it, you'll see that the work that should be done by the threads in order (prefixed with the letter "B" in the output) is indeed always in order, while the other work (prefixed with the letter "A") is executed in a random order.

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);
            }
        }
    }
}

这篇关于如何使用C#使线程按顺序通过门的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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