C#多线程--仓库问题引发的故事

  假设有这么个场景,一个仓库,里面有N件货物,现有六个搬运工(用线程模拟),其中2个向仓库放东西,4个往外搬东西。假设1秒能向里放2件货物,同时可向外搬3件货物(线程休眠),现在需要往里放M件货物,一旦仓库有货就要向外搬,这个东西怎么设计?

  这显然牵扯到线程同步的问题。本来,考虑的有点简单了,只用了一个锁,但结果是在执行一个动作的同时,另一个动作一直在等待(比如,放的时候,搬的线程等待放完后,才能开始运行),也就是在一秒内,只能放或者搬,这样的话,还不如一个线程全跑下来了,还省事。思考良久后,请教了一下,原来这种问题要放两个线程锁(对应两个动作),恍然大悟。好了,别的不说了,直接上这货的代码吧:假设N和M都为15,标准情况下需要放一个队列,现在只用最简单的数字来模拟吧

class Operator
    {
        static int pushNum = 20;
        static int num = 20;

        private object locker1 = new object();//这个锁负责往里放
        private object locker2 = new object();//这个锁负责往外拿

        public int Total
        {
            get { return num; }
        }

        public int PushTotal
        {
            get { return pushNum ; }
        }

        public void setPushNum(int t)
        {
            pushNum = t;
            lock (locker1)
            {
                Monitor.PulseAll(locker1);
            }
        }

        public void Push()
        {
            while (1 == 1)
            {
                lock (locker1)
                {
                    if (pushNum <= 0)
                    {
                        try
                        {
                            Monitor.Wait(locker1);
                        }
                        catch (SynchronizationLockException e)
                        {
                            Console.WriteLine(e);
                        }
                        catch (ThreadInterruptedException e)
                        {
                            Console.WriteLine(e);
                        }
                    }
                    else
                    {
                        Thread.Sleep(500);
                        pushNum--;
                        num++;
                   
                        Console.ForegroundColor = ConsoleColor.White;
                        Console.WriteLine("放入一件商品,此时还剩数量:{0},\t还需要放的数量:{1},\t搬运工:{2}", num, pushNum,
                   Thread.CurrentThread.Name);
lock (locker2) { Monitor.PulseAll(locker2); } } } } } public void Pull() { while (1 == 1) { lock (locker2) { if (num <= 0) { try { Monitor.Wait(locker2); } catch (SynchronizationLockException e) { Console.WriteLine(e); } catch (ThreadInterruptedException e) { Console.WriteLine(e); } } else { Thread.Sleep(333); num--; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("搬出一件商品,此时还剩商品数:{0}\t搬运工:{1}",num , Thread.CurrentThread.Name); } } } } }

  上面的红色字体显示了两个线程锁,以及激活其他线程的时间段,下面贴上主线程:

static void Main(string[] args)
        {
            Operator op=new Operator();

            Random r=new Random();

            Thread thread1 = new Thread(new ThreadStart(op.Push));
            thread1.Name = "push[1]";
            Thread thread2 = new Thread(new ThreadStart(op.Push));
            thread2.Name = "push[2]";
            //Thread thread3 = new Thread(new ThreadStart(op.Push));
            //thread3.Name = "push[3]";
            //Thread thread4 = new Thread(new ThreadStart(op.Push));
            //thread4.Name = "push[4]";

            Thread thread11 = new Thread(new ThreadStart(op.Pull));
            thread11.Name = "pull[1]";
            Thread thread12 = new Thread(new ThreadStart(op.Pull));
            thread12.Name = "pull[2]";
            Thread thread13 = new Thread(new ThreadStart(op.Pull));
            thread13.Name = "pull[3]";
            Thread thread14 = new Thread(new ThreadStart(op.Pull));
            thread14.Name = "pull[4]";

            try
            {

                thread1.Start();
                thread2.Start();
                //thread3.Start();
                //thread4.Start();

                thread11.Start();
                thread12.Start();
                thread13.Start();
                thread14.Start();

                do
                {
                        if (op.Total == 0&&op.PushTotal==0)
                    {
                        Console.WriteLine("是否继续放入 Y/N");
                        while (Console.ReadLine().ToUpper() == "Y")
                        {
                            Console.WriteLine("输入数量:");

                            int t;
                            Int32.TryParse(Console.ReadLine(), out t);
                            op.setPushNum(t);
                        }

                    }
                    else
                    {
                        Thread.Sleep(1000);
                    }
                } while (true);
            }
            catch (ThreadStateException e)
            {
                Console.WriteLine(e);
            }
            catch (ThreadInterruptedException e)
            {
                Console.WriteLine(e);
            }
        }

  效果图如下:

  当按下y后,继续激活等待的线程:

posted @ 2013-11-20 20:27  蚂蚁拉车  阅读(399)  评论(0编辑  收藏  举报