文档详情

第7章多线程程序设计详解.ppt

发布:2017-04-13约1.22万字共43页下载文档
文本预览下载声明
* * * * public void Fun2() { int k,n; for(k=0;k4;k++) {//如有线程进入此临界区,其他线程就不能进入这个临界区 lock(this) { n=num; //也不能进入前边的临界区 n++; Thread.Sleep(10); num=n; } Thread.Sleep(100); } } 编译运行,单击按钮标签控件应显示8。如果有多个共享数据区,使用此方法不太方便。 7.2.3 用Mutex类实现互斥 可以使用Mutex类对象保护共享资源(如上例中的总人数变量)不被多个线程同时访问。Mutex类WaitOne方法和ReleaseMutex方法之间代码是互斥体,这些代码要访问共享资源。Mutex类的WaitOne方法分配互斥体访问权,该方法只向一个线程授予对互斥体的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程用ReleaseMutex方法释放该互斥体。 【例7.6】使用Mutex类对象实现互斥。修改例7.4,为Form1类增加私有Mutex类变量:private Mutex mut。在Form1类构造函数中增加语句:mut=new Mutex();该句位置必须在建立线程语句之前。修改例7.4中的两个Fun1()和Fun2()方法如下: public void Fun1() { int k,n; for(k=0;k4;k++) { mut.WaitOne(); //等待互斥体访问权 n=num;// mut.WaitOne()和mut.ReleaseMutex()之间是互斥体 n++;//Mutex类对象mut的互斥体包含两部分,函数Fun1和Fun2中的互斥体 Thread.Sleep(10);//有线程进入一个互斥体,其他线程不能进入任何一个互斥体 num=n; mut.ReleaseMutex(); //释放互斥体访问权 Thread.Sleep(50); } }//退出该方法,线程结束 public void Fun2() { int k,n; for(k=0;k4;k++) { mut.WaitOne(); n=num; n++; Thread.Sleep(10); num=n; mut.ReleaseMutex(); Thread.Sleep(100); } } 编译,运行,标签控件显示8。如果有多个共享数据区,可以定义多个Mutex类对象。 7.2.4 用Monitor类实现互斥 也可以使用Monitor类保护共享资源不被多个线程或进程同时访问。Monitor类通过向单个线程授予对象锁来控制对对象的访问。只有拥有对象锁的线程才能执行临界区的代码,此时其他任何线程都不能获取该对象锁。只能使用Monitor类中的静态方法,不能创建Monitor类的实例。Monitor类中的静态方法主要有: 方法Enter:获取参数指定对象的对象锁。此方法放在临界区的开头。如其他线程已获取对象锁,则该线程将被阻塞,直到其他线程释放对象锁,才能获取对象锁。 方法Wait:释放参数指定对象的对象锁,以便允许其他被阻塞的线程获取对象锁。该线程进入等待状态,等待状态必须由其他线程用方法Pulse或PulseAll唤醒,使等待状态线程变为就绪状态。 方法Pulse和PulseAll:向等待线程队列中第一个或所有等待参数指定对象的对象锁的线程发送信息,占用对象锁的线程准备释放对象锁。执行方法Exit后将释放对象锁。 方法Exit:释放参数指定对象的对象锁。此操作还标记受对象锁保护的临界区的结尾。 使用Monitor类实现互斥也很简单,请读者修改例7_2_1,使用Monitor类实现互斥。Monitor类主要用来实现生产者和消费者关系中的线程的同步,具体例子见下一节。 7.3 生产者线程和消费者线程的同步 在生产者和消费者关系中,生产者线程产生数据,并把数据存到公共数据区,消费者线程使用数据,从公共数据区取出数据。显然如果公共数据区只能存一个数据,那么在消费者线程取出数据前,生产者线程不能放新数据到公共数据区,否则消费者线程将丢失数据。同样只有生产者线程把数据已经放到公共数据区,消费者线程才能取出数据,否则消费者线程不能取数据。这些就是所谓的生产者和消费者关系,必须要求生产者线程和消费者线程同步。 7.3.1 生产者线程和消费者线程不同步可能发生错误 【例7.7】下边的例子模拟生产者线程和消费者线程不同步可能发生错误。有一个公共变量,要求生产者线程顺序放1到4到这个公共变量中,每放一个变量,消费者线程取出这个数
显示全部
相似文档