代码改变世界

多线程编程(5)WaitEvent

2010-11-17 17:31  Clingingboy  阅读(1555)  评论(0编辑  收藏  举报

 

还是线程同步问题.

餐馆吃菜

即假设3个线程同步进行,但必须是有序进行的,不然线程就会错乱。比如

  1. 厨师烧菜
  2. 服务员端菜
  3. 顾客吃菜

上面的事情必须按照1,2,3的顺序来完成,意思即3在等2,2在等1.

顾客会一直催服务员,服务员会一直催厨师,如下示例

public class Demo3
{
    AutoResetEvent event1;
    AutoResetEvent event2;
    public Demo3()
    {
        event1 = new AutoResetEvent(false);
        event2 = new AutoResetEvent(false);
        ThreadPool.QueueUserWorkItem(new WaitCallback(Task1));
        ThreadPool.QueueUserWorkItem(new WaitCallback(Task2));
        ThreadPool.QueueUserWorkItem(new WaitCallback(Task3));
    }

    public void Task1(object obj)
    {
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("烧菜");
        Thread.Sleep(3000);
        event1.Set();
    }

    public void Task2(object obj)
    {
        event1.WaitOne();
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("端菜");
        Thread.Sleep(2000);
        event2.Set();
    }

    public void Task3(object obj)
    {
        event2.WaitOne();
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("吃菜);
    }
}

结果

image

通过这种方式就保持线程可以有条理的工作

组合模块(WaitAll)

就像开发程序一样,先是分模块开发,然后是合并

public class Demo4
{
    AutoResetEvent[] events;
    public Demo4()
    {
        events = new AutoResetEvent[]{
        new AutoResetEvent(false),
        new AutoResetEvent(false),
        new AutoResetEvent(false)
        };

        ThreadPool.QueueUserWorkItem(new WaitCallback(Task1));
        ThreadPool.QueueUserWorkItem(new WaitCallback(Task2));
        ThreadPool.QueueUserWorkItem(new WaitCallback(Task3));

        WaitHandle.WaitAll(events);
        Console.WriteLine("Complete");
    }

    public void Task1(object obj)
    {
        Thread.Sleep(1000);
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("Task1");
        events[0].Set();
    }

    public void Task2(object obj)
    {
        Thread.Sleep(2000);
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("Task2");
        events[1].Set();
    }

    public void Task3(object obj)
    {
        Thread.Sleep(3000);
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("Task3");
        events[2].Set();
    }
}

结果

image

秒杀商品(AutoReset)

现在假设有3个人抢1件商品,3个人在等的就是时间的开始,时间一开始就开始秒杀.但只有一人才能成功,即3个人是抢占的

使用AutoResetEvent(只能激活一个线程)完成,下面只有一个线程进来,至于是哪个,谁也不知道

public class Demo5
{
    EventWaitHandle eventHandle;
    public Demo5()
    {
        eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);

        ThreadPool.QueueUserWorkItem(new WaitCallback(Task1));
        ThreadPool.QueueUserWorkItem(new WaitCallback(Task2));
        ThreadPool.QueueUserWorkItem(new WaitCallback(Task3));

        eventHandle.Set();
    }

    public void Task1(object obj)
    {
        eventHandle.WaitOne();
        Thread.Sleep(1000);
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("Task1");
    }

    public void Task2(object obj)
    {
        eventHandle.WaitOne();
        Thread.Sleep(1000);
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("Task2");
    }

    public void Task3(object obj)
    {
        eventHandle.WaitOne();
        Thread.Sleep(1000);
        Console.WriteLine(DateTime.Now);
        Console.WriteLine("Task3");
    }
}

image

短跑比赛(ManualReset)

裁判员哨子一吹,全体运动员开跑,即ManualResetEvent可以激活多个线程,改为ManualResetEvent的结果如下

image

 

以上4个示例,展示了线程同步的问题