当前位置: 移动技术网 > IT编程>开发语言>c# > 5、线程的协作问题

5、线程的协作问题

2019年08月04日  | 移动技术网IT编程  | 我要评论

1、实例背景

  打印机做两件事情:

        第一件事件负责接受外界打印的请求,包括其他的电脑,把这个打印任务添加到打印队列当中。

        另一件事情就是打印,从打印队列中取出一个打印任务,完成打印任务,将这个打印任务去掉。

     可以肯定的是,这两件事情是并发进行的,不可能打印机一直去打印,而不去接受新的打印任务,也不可能一直接受请求,而不去打印,等到让油墨干了纸张烂掉了

如果我们用程序让打印机干活的话,显然我们可以用两个线程同时做这两件事情,当然还要考虑其他的事情,就是前面说的并发问题,因为存在着并发竞争资源--打印机队列。

我们希望的理想情况是最好两个线程能交替执行,即接受一次打印请求的操作,再执行一次打印的操作,而不是接受请求n次后才执行一次打印任务,所以说我们还需要解决线程之间配合工作的问题,也就是线程协作的问题。

 

关于线程协作,我们考虑三个问题:

(1)如何在当前线程中通知其他的线程的执行

(2)如何阻止当前线程的执行

(3)其他线程执行完毕如何继续当前线程的执行

   答案:(1monitor.pulse()

         (2)monitor.wait()

         (3)monitor.wait()

 

2没有线程协作的打印机工作

class monitortest

    {

        int max = 10;//最多允许10个打印作业

 

        queue<int> queue; //表示对象的先进先出的集合

        public monitortest()

        {

            queue = new queue<int>();

        }

 

        //生产者线程调用的方法:模拟添加打印作业

        public void producerthread()

        {

            random r = new random();

 

            lock (queue)

            {

                for (int counter = 0; counter < max; counter++)

                {

                    int value = r.next(100);

                    queue.enqueue(value);    //随机数入队列

                    console.writeline("生产:" + value);

                }

            }

        }

 

        //消费者线程

        public void consumerthread()

        {

            lock (queue)

            {

                for (int counter = 0; counter < max; counter++)

                {

                    int value = (int)queue.dequeue(); //第一个元素出队列

                    console.writeline("消费:" + value);

                }

            }

        }

 

        static void main(string[] args)

        {

            monitortest monitor = new monitortest();

            thread producer = new thread(new threadstart(monitor.producerthread));

            thread consumer = new thread(new threadstart(monitor.consumerthread));

 

            producer.start();

            consumer.start();

 

            console.writeline("打印机工作完毕");

            console.readline();

        }

    }

 

 

 

 

发现:先把所有的生产任务添加进来,然后再执行消费作业。这是不符合我们的要求的。我们要求是添加一个打印任务就执行一次消费作业

 

3有线程协作的打印机工作

 

 

  

class monitortest

    {

        int max = 10;//最多允许10个打印作业

 

        queue<int> queue; //表示对象的先进先出的集合

        public monitortest()

        {

            queue = new queue<int>();

        }

 

        //生产者线程调用的方法:模拟添加打印作业

        public void producerthread()

        {

            random r = new random();

 

            lock (queue)

            {

                for (int counter = 0; counter < max; counter++)

                {

                    int value = r.next(100);

                    queue.enqueue(value);    //随机数入队列

                    console.writeline("生产:" + value);

 

                    //producer线程通知consumer线程从阻塞队列进入准备队列

                    monitor.pulse(queue); //释放等待线程

                    //producer线程进入阻塞队列,并放弃了锁定,使consumer线程得以执行

                    monitor.wait(queue);  //等待cosumerthread()完成

 

                }

            }

        }

 

        //消费者线程

        public void consumerthread()

        {

            lock (queue)

            {

                do

                {

                    if (queue.count>0)

                    {

                        int value = (int)queue.dequeue(); //第一个元素出队列

                        console.writeline("消费:" + value);

 

                        monitor.pulse(queue);//释放

                    }

                } while (monitor.wait(queue)); // 等待producerthread()放入数据

            }

        }

 

        static void main(string[] args)

        {

            monitortest monitor = new monitortest();

            thread producer = new thread(new threadstart(monitor.producerthread));

            thread consumer = new thread(new threadstart(monitor.consumerthread));

 

            producer.start();

            consumer.start();

 

            console.writeline("打印机工作完毕");

            console.readline();

        }

    }

 

 

 

解释:

producer线程start启动后,进入运行状态后,产生了一个随机数,并添加到queue队列容器里,然后碰到代码 monitor.pulse(queue) ; 那么producer线程就通知线程consumer从阻塞队列进入准备队列。然后producer线程又碰到monitor.wait(queue); producer线程进入等待状态(即阻塞了自己),他放弃了对queue的锁定,所以线程consumer得以执行。

  那么线程consumer执行了,当执行到do**while循环处,由于第一次执行,所以不判断条件,直接从queue队列里“请出”第一个元素,然后他碰到代码monitor.pulse(queue) ; ,那么线程consumer就通知producer线程从阻塞队列进入准备队列,然后他判断whilemonitor.wait(queue); ),因为这是第一次执行,所以

 

 

 

结果显示是 生产者生产一个,消费者接着就消费一个。如此循环中。。。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网