C#之使用AutoResetEvent实现线程的顺序执行

前几天一朋友问我如何实现线程的顺序执行,说真的,虽然看过CLR这本书,也把线程部分拜读了两遍,可是这个问题出来以后仍是没有一个思路。今天在搜索资料的时候无心中再次看到AutoResetEvent这个东西,固然我知道它是和线程有关,用于处理线程切换之类的(可能在测试Demo以前理解有误),因而决定用AutoResetEvent来处理上面的问题。多线程

这里以园区一个园友的例子来讲明,这个例子就是 买书--》付款--》拿书这个过程,该过程会持续n(经过变量设置)次,而且每一次都要按照顺序执行,有可能有同窗会疑问,直接Sleep不就行了,干吗非要多个线程,若是处理某一个环节的时间太久或者是业务复杂,那么整个程序就直接未响应了,因此这里加入多线程来保证程序的响应。测试

class Program
    {
        //循环次数
        const int numIterations = 10;
        //买书
        static AutoResetEvent buyResetEvent = new AutoResetEvent(false);
        //付款
        static AutoResetEvent payResetEvent = new AutoResetEvent(false);
        //取书
        static AutoResetEvent getBookEvent = new AutoResetEvent(false);
       //循环的次数
        static int number;
        static void Main(string[] args)
        {
            //付款线程
            Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc));
            payMoneyThread.Name = "付钱线程";

            //取书线程
            Thread getBookThread = new Thread(new ThreadStart(GetBookProc));
            getBookThread.Name = "取书线程";

            payMoneyThread.Start();
            getBookThread.Start();

            for (int i = 1; i <= numIterations; i++)
            {
                Console.WriteLine("买书线程:数量{0}", i);
                number = i;
                //容许付款线程等待
                payResetEvent.Set();
                //禁止买书线程等待
                buyResetEvent.WaitOne();
            }
            Console.Read();
        }

        static void PayMoneyProc()
        {
            while (true)
            {
                //等待付款
                payResetEvent.WaitOne();
                Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
                //容许取书线程等待
                getBookEvent.Set();
            }
        }
        static void GetBookProc()
        {
            while (true)
            {
                //等待付款
                getBookEvent.WaitOne();      
                Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
                Console.WriteLine("------------------------------------------");
                //容许买书线程等待(到这一步一个完整的买书流程就执行结束了,彻底按照买书--》付款--》取书的流程)
                buyResetEvent.Set();
            }
        }
    }

上述代码不复杂,可是有几个关键的对象和方法,接下来详细进行说明。spa

1.分别定义了买书、付款、拿书三个AutoResetEvent,注意定义的时候传入了false,这也AutoSet默认是不可用的,须要手动调用Set方法才能够呢。该对象是决定是否能WaitOne一个请求的关键,当AutoResetEvent.Set执行则可使用AutoResetEvent.WaitOne进行一个等待请求,若是再有WaitOne请求,则要继续等待Set的执行;.net

2.先看for循环,在循环中咱们使用payResetEvent.Set()这句代码,这也PayThread中的WaitOne请求就能够得到批准(下文有介绍),同时咱们又加上了buyResetEvent.WaitOne()(这样在上一次购买流程结束以前,新的一次流程是不能够执行的,这也就是咱们的最大问题,保证线程按照顺序执行);线程

3.定义了付款和拿书的Thread,而且在方法内都是While循环,该循环主要是为了能够将咱们的过程进行屡次,毕竟线程只会执行一遍嘛。固然这个不是重点,重点是While中咱们的操做,先看PayThrea的操做,先调用payResetEvent.WaitOne()请求一个等待操做,固然能够立马执行,由于在 2 中咱们说了for中是调用了payResetEvent.Set()操做,这样就能够直接获得一个请求响应,输出关键信息,而后又到了重点,咱们调用了getBookEvent.Set(),这是为何呢,由于付款不成功是不能够拿书走的啊,那样就是偷盗了。注意、注意、注意,重要的话说三遍,GetBookThread操做中也有一个waitOne请求,但是为何不会执行呢,由于没有Set呢,咱们初始化AutoResetEvent的时候咱们设置的是false,这样默认就不能够获得一个请求,必须手动调用Set才能够,因为在PayMoneyThread的最后一行代码中咱们调用了getBookEvent.Set(),这样getBookEvent.WaitOne就可用了。在GetBookThread中依次输出关键信息,最后一行代码又来了,再次调用了一个AutoResetEvent.Set(),没错就是买书的对象,由于到了这一步完整的买书流程就结束了,能够再次买书了啊啊啊啊啊啊,能够买书了,好开心啊。而后再次回到for循环中的最后一行代码,buyResetEvent.Wait()此时就复活了,开始第好几回的买书流程。code

运行截图以下(绝对真实,毫无PS):对象

好了,退朝,有事改天上朝再议。blog

 

Update:鉴于你们对这个使用方式有不一样的建议,另外.net的版本都4.6了,因此从新使用Task的方式进行了更新,欢迎继续拍砖.get

 

 static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Task buyTask = Task.Factory.StartNew(() =>
                {
                    BuyBook();
                }).ContinueWith((state) =>
                {
                    PayMoney();
                }).ContinueWith((state) =>
                {
                    TakeBook();
                });
                Task.WaitAll(buyTask);
                Console.WriteLine();
            }

            Console.Read();
        }

        private static void BuyBook()
        {
            Console.WriteLine("书太多了,挑花眼了");
        }

        private static void PayMoney()
        {
            Console.WriteLine("先付钱才能取书哦");
        }

        private static void TakeBook()
        {
            Console.WriteLine("取书喽");
        }
相关文章
相关标签/搜索