Windows下进程同步与互斥

合集下载

实验1编程实现进程(线程)同步和互斥

实验1编程实现进程(线程)同步和互斥

实验1编程实现进程(线程)同步和互斥一、实验目的①通过编写程序实现进程同步和互斥,使学生掌握有关进程(线程)同步与互斥的原理,以及解决进程(线程)同步和互斥的算法,从而进一步巩固进程(线程)同步和互斥②等有关的内容。

③了解Windows2000/XP中多线程的并发执行机制,线程间的同步和互斥。

④学习使用Windows2000/XP中基本的同步对象,掌握相应的⑤API函数。

⑥掌握进程和线程的概念,进程(线程)的控制原语或系统调用的使用。

⑦掌握多道程序设计的基本理论、方法和技术,培养学生多道程序设计的能力。

二、实验内容在Windows XP、Windows 2000等操作系统下,使用的VC、VB、java或C等编程语言,采用进程(线程)同步和互斥的技术编写程序实现生产者消费者问题或哲学家进餐问题或读者-写者问题或自己设计一个简单进程(线程)同步和互斥的实际问题。

三、实验要求①经调试后程序能够正常运行。

②采用多进程或多线程方式运行,体现了进程(线程)同步和互斥的关系。

③程序界面美观。

四、实验步骤、过程让写者与读者、读者与读者之间互斥的访问同一数据集,在无写者进程到来时各读者可同时的访问数据集,在读者和写者同时等待时写者优先唤醒。

设置两个全局变量readcount 和writecount来记录读者与写者的数目,设置了3个信号量。

h_mutex1表示互斥对象对阻塞在read这一个过程实现互斥,h_mutex2实现全局变量readcount操作上的互斥,h_mutex3实现对全局变量writecount的互斥访问。

设置了两个临界区,为了实现写者优先,用了临界区read。

数据结构:(1)用了两个临界区(2)自定义结构ThreadInfo记录一条线程信息,多个线程对应一个ThreadInfo数组。

(3)设置了互斥量h_mutex1,实现了互斥对象对阻塞read这一过程,h_mutex2实现对readcount操作的互斥,h_mutex3实现对writecount的互斥访问。

操作系统同步和互斥

操作系统同步和互斥

操作系统同步和互斥操作系统中的进程之间的关系只有两种:同步与互斥。

下面由店铺为大家整理了操作系统的同步和互斥的相关知识,希望对大家有帮助!操作系统同步和互斥1.进程同步进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。

进程间的直接制约关系来源于他们之间的合作。

比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。

而当进程A产生信息放入缓冲区时,进程B才会被唤醒。

2.进程互斥进程互斥是进程之间的间接制约关系。

当一个进程进入临界区使用临界资源时,另一个进程必须等待。

只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。

比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。

扩展:临界资源在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。

但对于某些资源来说,其在同一时间只能被一个进程所占用。

这些一次只能被一个进程所占用的资源就是所谓的临界资源。

典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。

对于临界资源的访问,必须是互诉进行。

也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。

而进程内访问临界资源的代码被成为临界区。

对于临界区的访问过程分为四个部分:1.进入区:查看临界区是否可访问,如果可以访问,则转到步骤二,否则进程会被阻塞2.临界区:在临界区做操作3.退出区:清除临界区被占用的标志4.剩余区:进程与临界区不相关部分的代码临界资源使用规则:忙则等待、优先等待、空闲让进、让权等待(在临界区的进程,不能在临界区内长时间处于事件等待,必须在一定时间退出临界区)。

进程间同步的几种方法

进程间同步的几种方法

进程间同步的几种方法进程间同步是指两个或多个进程之间进行协调,以确保它们能够正确地执行。

这是多任务操作系统中的重要问题,因为进程之间共享资源,包括内存、文件和网络连接等。

进程同步的关键是确保一组进程在处理共享资源时,能够避免发生竞态条件(Race Condition)和死锁(Deadlock)。

竞态条件指多个进程同时访问共享资源,导致不正确的结果。

死锁指多个进程互相等待,导致它们都无法继续执行。

1. 互斥锁互斥锁是最常见的同步方法之一,它被用来保护共享资源,确保同一时刻只有一个进程可以访问它。

当一个进程获取了锁,其他进程必须等待,直到锁被释放。

在 POSIX 系统中,互斥锁可以通过 pthread_mutex_t 数据类型实现。

我们可以使用pthread_mutex_init() 函数初始化锁,使用 pthread_mutex_lock() 函数获取锁,使用pthread_mutex_unlock() 函数释放锁。

下面是一个例子,展示了如何使用互斥锁同步两个进程对共享变量的访问:```c#include <pthread.h>#include <stdio.h>int count = 0;pthread_mutex_t lock;void *increment(void *arg) {for (int i = 0; i < 1000000; i++) {pthread_mutex_lock(&lock); // 获取锁count++;pthread_mutex_unlock(&lock); // 释放锁}return NULL;}在上面的例子中,我们创建了两个线程,它们分别对共享变量 count 进行了一百万次的递增操作。

我们使用了互斥锁来保护 count 变量,确保同一时刻只有一个线程可以访问它。

2. 信号量3. 条件变量条件变量可以被用来支持更高级的同步机制,如互斥锁和信号量。

进程之间同步和互斥的区别和联系

进程之间同步和互斥的区别和联系

进程之间同步和互斥的区别和联系
进程之间同步和互斥是操作系统中常见的概念,它们之间有一定的区别和联系。

同步是指多个进程之间的协调,以便它们能够有序地执行。

同步的目的是保证数据的一致性,避免出现数据竞争的情况。

同步可通过共享变量、信号量等方式实现,实现同步的方法包括互斥、条件变量等。

互斥是一种同步机制,用于保护共享资源,防止多个进程同时访问同一资源。

互斥的实现通常是通过临界区实现的,即对于一段代码,只允许一个进程访问,其他进程需要等待。

互斥能够避免多个进程同时写入共享资源,保证了数据的正确性。

同步和互斥的联系在于它们都是为了保证多个进程之间的协调
和数据的正确性。

同步和互斥都是通过对共享资源进行限制来实现的,区别在于同步是为了保证进程的顺序执行,而互斥是为了保证共享资源的安全性。

总的来说,同步和互斥都是操作系统中非常重要的概念,它们的合理运用可以提高操作系统的性能和稳定性。

- 1 -。

详解进程同步与互斥机制

详解进程同步与互斥机制

详解进程同步与互斥机制⽬录⼀、什么是进程同步⼆、什么是进程互斥三、常见的进程同步与互斥机制⼀、什么是进程同步在多道批处理系统中,多个进程是可以并发执⾏的,但由于系统的资源有限,进程的执⾏不是⼀贯到底的,⽽是⾛⾛停停,以不可预知的速度向前推进,这就是进程的异步性。

那么,进程的异步性会带来什么问题呢?举个例⼦,如果有 A、B 两个进程分别负责读和写数据的操作,这两个线程是相互合作、相互依赖的。

那么写数据应该发⽣在读数据之前。

⽽实际上,由于异步性的存在,可能会发⽣先读后写的情况,⽽此时由于缓冲区还没有被写⼊数据,读进程 A 没有数据可读,因此读进程 A 被阻塞。

进程同步(synchronization)就是⽤来解决这个问题的。

从上⾯的例⼦我们能看出,⼀个进程的执⾏可能影响到另⼀个进程的执⾏,所谓进程同步就是指协调这些完成某个共同任务的并发线程,在某些位置上指定线程的先后执⾏次序、传递信号或消息。

再举个⽣活中的进程同步的例⼦,你想要喝热⽔,于是你打了⼀壶⽔开始烧,在这壶⽔烧开之前,你只能⼀直等着,⽔烧开之后⽔壶⾃然会发⽣响声提醒你来喝⽔,于是你就可以喝⽔了。

就是说⽔烧开这个事情必须发⽣在你喝⽔之前。

注意不要把进程同步和进程调度搞混了:进程调度是为了最⼤程度的利⽤ CPU 资源,选⽤合适的算法调度就绪队列中的进程。

进程同步是为了协调⼀些进程以完成某个任务,⽐如读和写,你肯定先写后读,不能先读后写吧,这就是进程同步做的事情了,指定这些进程的先后执⾏次序使得某个任务能够顺利完成。

⼆、什么是进程互斥同样的,也是因为进程的并发性,并发执⾏的线程不可避免地需要共享⼀些系统资源,⽐如内存、打印机、摄像头等。

举个例⼦:我们去学校打印店打印论⽂,你按下了 WPS 的 “打印” 选项,于是打印机开始⼯作。

你的论⽂打印到⼀半时,另⼀位同学按下了 Word 的 “打印” 按钮,开始打印他⾃⼰的论⽂。

想象⼀下如果两个进程可以随意的、并发的共享打印机资源,会发⽣什么情况?显然,两个进程并发运⾏,导致打印机设备交替的收到 WPS 和 Word 两个进程发来的打印请求,结果两篇论⽂的内容混杂在⼀起了。

四种进程或线程同步互斥的控制方法

四种进程或线程同步互斥的控制方法

四种进程或线程同步互斥的控制方法1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。

2、互斥量:为协调共同对一个共享资源的单独访问而设计的。

3、信号量:为控制一个具有有限数量用户资源而设计。

4、事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。

一临界区临界区的使用在线程同步中应该算是比较简单,说它简单还是说它同后面讲到的其它方法相比更容易理解。

举个简单的例子:比如说有一个全局变量(公共资源)两个线程都会对它进行写操作和读操作,如果我们在这里不加以控制,会产生意想不到的结果。

假设线程A 正在把全局变量加1然后打印在屏幕上,但是这时切换到线程B,线程B又把全局变量加1然后又切换到线程A,这时候线程A打印的结果就不是程序想要的结果,也就产生了错误。

解决的办法就是设置一个区域,让线程A在操纵全局变量的时候进行加锁,线程B如果想操纵这个全局变量就要等待线程A释放这个锁,这个也就是临界区的概念。

二互斥体windows api中提供了一个互斥体,功能上要比临界区强大。

也许你要问,这个东东和临界区有什么区别,为什么强大?它们有以下几点不一致:1.critical section是局部对象,而mutex是核心对象。

因此像waitforsingleobject是不可以等待临界区的。

2.critical section是快速高效的,而mutex同其相比要慢很多3.critical section使用范围是单一进程中的各个线程,而mutex由于可以有一个名字,因此它是可以应用于不同的进程,当然也可以应用于同一个进程中的不同线程。

4.critical section 无法检测到是否被某一个线程释放,而mutex在某一个线程结束之后会产生一个abandoned的信息。

同时mutex只能被拥有它的线程释放。

下面举两个应用mutex 的例子,一个是程序只能运行一个实例,也就是说同一个程序如果已经运行了,就不能再运行了;另一个是关于非常经典的哲学家吃饭问题的例子。

实验一进程的同步与互斥

实验一进程的同步与互斥

实验一进程的同步与互斥一、实验目的(1)加深对进程概念的理解,明确进程和程序的区别。

(2)进一步认识并发执行的实质。

(3)分析进程竞争资源现象,学习解决进程互斥的法。

(4)了解Windows对进程管理的支持。

二、实验类型观察/分析型。

三、预习内容预习进程管理有关理论和VC++对进程管理的支持, 包括进程的基本操作和经典的进程同步与互斥问题。

四、实验要求本实验通过学习和分析三个简单的Windows 线程编程编写一个简单的生产者/消费者问题实例程序。

利用(1)和(2)中的Windows 进程和线程创建法实现一个简单的读者,写者程序,读者将1~10 十个数字依次填入临界资源区gData,当且仅当gData 被读者消费后,写者才可以写入下一个数。

五、实验代码#include "windows.h"#include <conio.h>#include <stdio.h>#include <math.h>const int writerNum = 1;const int readerNum = 1;int gData = 0;bool continu = true;HANDLE hmutex;HANDLE hfullsemaphore;HANDLE hemptysemaphore;DWORD WINAPI reader(LPVOID lppara){while(continu){WaitForSingleObject(hemptysemaphore,INFINITE);WaitForSingleObject(hmutex,INFINITE);if(gData >= 11){continu = false;break;}Sleep(100);printf("readers gets data:%d\n", gData);printf("\n");ReleaseMutex(hmutex);ReleaseSemaphore(hfullsemaphore,1,NULL);}return NULL;}DWORD WINAPI writer(LPVOID lppara){while(continu){WaitForSingleObject(hfullsemaphore,INFINITE);WaitForSingleObject(hmutex,INFINITE);if(gData >= 10){continu = false;break;}Sleep(100);gData++;printf("writer gets data:%d\n", gData);printf("\n");ReleaseMutex(hmutex);ReleaseSemaphore(hemptysemaphore,1,NULL);}return NULL;}int main(){hmutex = CreateMutex(NULL,false,NULL);hfullsemaphore = CreateSemaphore(NULL,1,1,NULL);hemptysemaphore = CreateSemaphore(NULL,0,1,NULL);DWORD readerdata;DWORD writerdata;for (int i=0;i<writerNum;i++){if(CreateThread(NULL,0,writer,NULL,0,&writerdata)==NULL) return -1;}for (int j=0;j<readerNum;j++){if(CreateThread(NULL,0,reader,NULL,0,&readerdata)==NULL) return -1;}printf("Program ends successfully\n");return 0;}。

《操作系统》课程实验报告

《操作系统》课程实验报告

《操作系统》课程实验报告一、实验目的本次《操作系统》课程实验的主要目的是通过实际操作和观察,深入理解操作系统的工作原理、进程管理、内存管理、文件系统等核心概念,并掌握相关的操作技能和分析方法。

二、实验环境1、操作系统:Windows 10 专业版2、开发工具:Visual Studio Code3、编程语言:C/C++三、实验内容(一)进程管理实验1、进程创建与终止通过编程实现创建新进程,并观察进程的创建过程和资源分配情况。

同时,实现进程的正常终止和异常终止,并分析其对系统的影响。

2、进程同步与互斥使用信号量、互斥锁等机制实现进程之间的同步与互斥。

通过模拟多个进程对共享资源的访问,观察并解决可能出现的竞争条件和死锁问题。

(二)内存管理实验1、内存分配与回收实现不同的内存分配算法,如首次适应算法、最佳适应算法和最坏适应算法。

观察在不同的内存请求序列下,内存的分配和回收情况,并分析算法的性能和优缺点。

2、虚拟内存管理研究虚拟内存的工作原理,通过设置页面大小、页表结构等参数,观察页面的换入换出过程,以及对系统性能的影响。

(三)文件系统实验1、文件操作实现文件的创建、打开、读取、写入、关闭等基本操作。

观察文件在磁盘上的存储方式和文件系统的目录结构。

2、文件系统性能优化研究文件系统的缓存机制、磁盘调度算法等,通过对大量文件的读写操作,评估不同优化策略对文件系统性能的提升效果。

四、实验步骤(一)进程管理实验步骤1、进程创建与终止(1)使用 C/C++语言编写程序,调用系统函数创建新进程。

(2)在子进程中执行特定的任务,父进程等待子进程结束,并获取子进程的返回值。

(3)通过设置异常情况,模拟子进程的异常终止,观察父进程的处理方式。

2、进程同步与互斥(1)定义共享资源和相关的信号量或互斥锁。

(2)创建多个进程,模拟对共享资源的并发访问。

(3)在访问共享资源的关键代码段使用同步机制,确保进程之间的正确协作。

(4)观察并分析在不同的并发情况下,系统的运行结果和资源竞争情况。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验进程同步与互斥一、实验目的1.掌握基本的同步与互斥算法,理解生产者消费者模型。

2.学习使用Windows 2000/XP中基本的同步对象,掌握相关API的使用方法。

3.了解Windows 2000/XP中多线程的并发执行机制,实现进程的同步与互斥。

二、实验内容及要求1.实验内容以生产者/消费者模型为依据,在Windows 2000环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。

2.实验要求●学习并理解生产者/消费者模型及其同步/互斥规则;●学习了解Windows同步对象及其特性;●熟悉实验环境,掌握相关API的使用方法;●设计程序,实现生产者/消费者进程(线程)的同步与互斥;●提交实验报告。

三、相关知识介绍1.同步对象同步对象是指Windows中用于实现同步与互斥的实体,包括信号量(Semaphore)、互斥量(Mutex)、临界区(Critical Section)和事件(Events)等。

本实验中使用到信号量、互斥量和临界区三个同步对象。

同步对象的使用步骤:●创建/初始化同步对象。

●请求同步对象,进入临界区(互斥量上锁)。

●释放同步对象(互斥量解锁)。

这些对象在一个线程中创建,在其他线程中都可以使用,实现同步与互斥。

2.相关API的功能及使用我们利用Windows SDK提供的API编程实现实验题目要求,而VC中包含有Windows SDK的所有工具和定义。

要使用这些API,需要包含堆这些函数进行说明的SDK头文件——最常见的是Windows.h(特殊的API调用还需要包含其他头文件)。

下面给出的是本实验使用到的API的功能和使用方法简单介绍。

(1) CreateThread●功能——创建一个在调用进程的地址空间中执行的线程●格式HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParamiter,DWORD dwCreationFlags,Lpdword lpThread );●参数说明lpThreadAttributes——指向一个LPSECURITY_ATTRIBUTES(新线程的安全性描述符)。

dwStackSize——定义原始堆栈大小。

lpStartAddress——指向使用LPTHRAED_START_ROUTINE类型定义的函数。

lpParamiter——定义一个给进程传递参数的指针。

dwCreationFlags——定义控制线程创建的附加标志。

lpThread——保存线程标志符(32位)(2) CreateMutex●功能——创建一个命名或匿名的互斥量对象●格式HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);●参数说明lpMutexAttributes——必须取值NULL。

bInitialOwner——指示当前线程是否马上拥有该互斥量(即马上加锁)。

lpName——互斥量名称。

(3) CreateSemaphore●功能——创建一个命名或匿名的信号量对象●格式HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,LONG lInitialCount,LONG lMaximumCount,LPCTSTR lpName );●参数说明lpSemaphoreAttributes——必须取值NULL。

lInitialCount——信号量的初始值。

该值大于0,但小于lMaximumCount指定的最大值。

lMaximumCount——信号量的最大值。

lpName——信号量名称。

(4) WaitForSingleObject●功能——使程序处于等待状态,直到信号量hHandle出现(即其值大于等于1)或超过规定的等待时间●格式DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);●参数说明hHandle——信号量指针。

dwMilliseconds——等待的最长时间(INFINITE为无限等待)。

(5) ReleaseSemaphore●功能——对指定信号量加上一个指定大小的量。

成功执行则返回非0值●格式BOOL ReleaseSemaphore(HANDLE hSemaphore,LONG lReleaseCount,LPLONG lppreviousCount );●参数说明hSemaphore——信号量指针。

lReleaseCount——信号量的增量。

lppreviousCount——保存信号量当前值。

(6) ReleaseMutex●功能——打开互斥锁,即把互斥量加1。

成功调用则返回0●格式BOOL ReleaseMutex(HANDLE hMutex);●参数说明hMutex——互斥量指针。

(7) InitializeCriticalSection●功能——初始化临界区对象●格式VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);●参数说明lpCriticalSection——指向临界区对象的指针。

(8) EnterCriticalSection●功能——等待指定临界区对象的所有权●格式VOID enterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);●参数说明lpCriticalSection——指向临界区对象的指针。

(9) LeaveCriticalSection●功能——释放指定临界区对象的所有权●格式VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);●参数说明lpCriticalSection——指向临界区对象的指针。

四、实验示例(方法、步骤与例程)1.测试用例文件测试用例文件用于描述各线程的有关信息,该文件内容及格式如下:31 P 32 P 43 C4 14 P 25 C 3 1 2 4说明:第一行给出的是程序中设置的临界区个数;其余各行是各进程信息。

每行中的数据之间用Tab键分隔。

第一列(除第一行外):线程号。

第二列:P——生产者,C——消费者。

第三列:线程在生产和消费前的休眠时间,单位为秒。

第四及以后各列:消费的产品所对应的生产者线程号。

2.数据结构(1) 用整型数组Buffer_Critical表示缓冲区。

(2) 用自定义结构ThreadInfo记录一条线程信息,多个线程对应一个ThreadInfo数组。

(3) 通过如下同步对象实现互斥:●设一个互斥量h-mutex,实现生产者在查询和保留缓冲区的下一个空位置时进行互斥。

●设置h_Semaphore[MAX_THREAD_NUM]信号量数组表示相应产品已经生产,实现生产者与消费者之间的同步。

同时,用表示空缓冲区树木的信号量empty_semephore指示是否存在空位置,实现类似的同步,以便开始下一个产品的生产。

●设置临界区对象数组PC_Critical[MAX_BUFFER_NUM]实现每个缓冲区上消费者之间的互斥。

3.程序结构为了方便,程序结构用如下的文字予以描述。

(1) 主函数(2) 初始化缓冲区、消费请求队列及部分同步对象(3) 提取线程信息(4) 完成线程相关同步对象的初始化(5) 创建线程,模拟生产者和消费者(6) 等待所有线程结束(7) 程序结束(8) 消费者(9) 有无消费请求?有,则继续(10);无,则转(16)(10) 此请求可满足?可满足,转(11);否,则阻塞,再转(10)(11) 确定产品位置(12) 此产品正被消费?是,则阻塞,再转(12);否,则转(13)(13) 进入临界区(请求同一产品的消费者之间互斥)(14) 消费产品,并判断是否应该释放产品所占缓冲区(15) 退出临界区,转(9)(16) 结束消费者线程(17) 生产者(18) 存在空缓冲区?有,则继续(19);无,则阻塞,再转(18)(19) 另一生产者在写?否,则转(20);是,则阻塞,再转(19)(20) 进入临界区(请求同一产品的生产者之间互斥)(21) 在缓冲区中为本线程产品分配空间(22) 退出临界区(23) 写入产品到分配的缓冲区空间中(24) 结束生产者线程4.示例程序//**************************R_WP1.CPP*******************************// #include<windows.h>#include<fstream.h>#include<stdio.h>#include<string>#include<conio.h>//本程序允许的最大临界区数#define MAX_BUFFER_NUM 10//秒到微秒的乘法因子#define INTE_PER_SEC 1000//生产和消费进程总数#define MAX_THREAD_NUM 64//定义记录在测试文件中的线程参数数据结构struct ThreadInfo{int serial;char entity;double delay;int thread_request[MAX_THREAD_NUM];int n_request;};//全局变量定义//临界区对象的声明,用于管理缓冲区的互斥访问CRITICAL_SECTION PC_Critical[MAX_BUFFER_NUM];int Buffer_Critical[MAX_BUFFER_NUM]; //缓冲区声明HANDLE h_Thread[MAX_THREAD_NUM]; //存储线程句柄的数组ThreadInfo Thread_Info[MAX_THREAD_NUM]; //线程信息数组HANDLE empty_semaphore; //信号量HANDLE h_mutex; //互斥量DWORD n_Thread=0; //实际线程数目DWORD n_Buffer_or_Critical; //实际缓冲区/临界区数目HANDLE h_Semaphore[MAX_THREAD_NUM]; //生产者允许消费的信号量//生产、消费及辅助函数的声明void Produce(void *p);void Consume(void *p);bool IfInOtherRequest(int);int FindProducePosition();int FindBufferPosition(int);int main(void){DWORD wait_for_all;FILE *inFile; //ifstream inFile;int i,j,k;//初始化缓冲区for(i=0;i<MAX_BUFFER_NUM;i++)Buffer_Critical[i]=-1;//初始化各线程的请求队列for(j=0;j<MAX_THREAD_NUM;j++){for(k=0;k<MAX_THREAD_NUM;k++)Thread_Info[j].thread_request[k]=1;Thread_Info[j].n_request=0;}//初始化临界区对象for(i=0;i<MAX_BUFFER_NUM;i++)InitializeCriticalSection(&PC_Critical[i]);//打开输入文件,提取线程信息inFile=fopen("test.txt","r");//从文件中获得实际缓冲区数目fscanf(inFile,"%d",&n_Buffer_or_Critical);//inFile.get();printf("输入文件是:\n");//回显获得的缓冲区数目printf("%d \n",(int)n_Buffer_or_Critical);//提取各线程信息到相应的数据结构中while(!feof(inFile)){fscanf(inFile,"%d",&Thread_Info[n_Thread].serial);fscanf(inFile,"%d",&Thread_Info[n_Thread].entity);fscanf(inFile,"%d",&Thread_Info[n_Thread].delay);char c;fscanf(inFile,"%c",&c);while(c!='\n'&&!feof(inFile)){fscanf(inFile,"%d",&Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_reques t++]);fscanf(inFile,"%c",&c);;}n_Thread++;}//回显获得的线程信息,便于确认正确性for(j=0;j<(int)n_Thread;j++){int Temp_serial=Thread_Info[j].serial;char Temp_entity=Thread_Info[j].entity;double Temp_delay=Thread_Info[j].delay;printf(" \n thread%2d %c %f",Temp_serial,Temp_entity,Temp_delay);int Temp_request=Thread_Info[j].n_request;for(int k=0;k<Temp_request;k++)printf(" %d ",Thread_Info[j].thread_request[k]);cout<<endl;}printf("\n\n");//创建模拟过程中必要的信号量empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Critical, n_Buffer_or_Critical, "semephore_for_empty");h_mutex=CreateMutex(NULL,FALSE, "mutex_for_update");//用线程ID为产品读写时所使用的同步信号量命名for(j=0;j<(int)n_Thread;j++){std::string lp="semephore_for_produce";int temp=j;while(temp){char c=(char)(temp%10);lp+=c;temp/=10;}h_Semaphore[j+1]=CreateSemaphore(NULL,0,n_Thread,lp.c_str());}//创建生产者和消费者线程for(i=0;i<(int)n_Thread;i++){if(Thread_Info[i].entity=='P')h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce),&(Thread_ Info[i]),0,NULL);h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume),&(Thread _Info[i]),0,NULL);}//主程序等待各个线程的动作结束wait_for_all=WaitForMultipleObjects(n_Thread,h_Thread,TRUE,-1);printf(" \n \nALL Producer and Consumer have finished their work, \n");printf("Press any key to quit!\n");return 0;}//确认是否还有对同一产品的消费请求未执行bool IfInOtherRequest(int req){for(int i=0;i<n_Thread;i++)for(int j=0;j<Thread_Info[i].n_request;j++)if(Thread_Info[i].thread_request[j]==req)return TRUE;return FALSE;}//找出当前可以进行产品生产的空缓冲区位置int FindProducePosition(){int EmptyPosition;for(int i=0;i<n_Buffer_or_Critical;i++)if(Buffer_Critical[i]=-1){EmptyPosition=i;//用下列特殊值表示本缓冲区正处于被写状态Buffer_Critical[i]=-2;break;}return EmptyPosition;}//找出当前需要生产者生产的产品的位置int FindBufferPosition(int ProPos){int TempPos;for(int i=0;i<n_Buffer_or_Critical;i++)if(Buffer_Critical[i]=ProPos){TempPos=i;break;}return TempPos;}//生产者线程void Produce(void *p){//局部变量声明DWORD wait_for_semaphore,wait_for_mutex,m_delay;int m_serial;//获得本线程信息m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC);Sleep(m_delay);//开始请求生产printf("Producer %2d sends the produce require.\n",m_serial);//确认有空缓冲区,同时把空位置数empty减1,用于生产/消费同步wait_for_semaphore=WaitForSingleObject(empty_semaphore,-1);//互斥访问下一个用于生产的空临界区,实现写写互斥wait_for_mutex= WaitForSingleObject(h_mutex,-1);int ProducePos=FindProducePosition();ReleaseMutex(h_mutex);//生产者在获得的空位置做标记,以下的写操作在生产者之间可以并发执行//在核心生产步骤中,程序用生产者的ID作为产品编号供消费者识别printf("Producer %2d begin to produce at position %2d.\n",m_serial,ProducePos);Buffer_Critical[ProducePos]=m_serial;printf("Producer %2d finish producing :\n",m_serial);printf("Position[ %2d ]:%3d \n",ProducePos,Buffer_Critical[ProducePos]);//实现读写同步ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL);}//消费者线程void Consume(void *p){//局部变量声明DWORD wait_for_semaphore,m_delay;int m_serial,m_requestNum; //消费者序列号和请求的数目int m_thread_request[MAX_THREAD_NUM];//本消费线程的请求队列//提取本线程的信息m_serial=((ThreadInfo*)(p))->serial;m_delay=(DWORD)(((ThreadInfo*)(p))->delay *INTE_PER_SEC);m_requestNum=((ThreadInfo*)(p))->n_request;for(int i=0;i<m_requestNum;i++)m_thread_request[i]=((ThreadInfo*)(p))->thread_request[i];Sleep(m_delay);//循环进行所需产品的生产for(i=0;i<m_requestNum;i++){//请求消费下一个产品printf(" Consumer %2d request to consume %2d product\n",m_serial,m_thread_request[i]);//若生产者未生产,则等待;//若生产了,允许消费数目为-1;实现读写同步wait_for_semaphore=WaitForSingleObject(h_Semaphore[m_thread_request[i]],-1);//查询所需产品在缓冲区的号int BufferPos=FindBufferPosition(m_thread_request[i]);//开始消费,读读互斥//进入临界区消费,消费完毕通知其他消费者自己的请求已满足//若产品消费完,应做相应处理,并给出提示//相应处理是指把相应的缓冲区清空,并增加代表空缓冲区的信号量EnterCriticalSection(&PC_Critical[BufferPos]);printf("Consumer%2d begin to cosume %2d product\n",m_serial,m_thread_request[i]);((ThreadInfo*)(p))->thread_request[i]=-1;if(!IfInOtherRequest(m_thread_request[i])){Buffer_Critical[BufferPos]=-1; //标记缓冲区为空printf("Consumer%2d finish consuming %2d:\n", m_serial,m_thread_request[i]);printf("position[%2d]:%3d\n",BufferPos,Buffer_Critical[BufferPos]);ReleaseSemaphore(empty_semaphore,1,NULL);}elseprintf("Consumer %2d finish consuming product %2d\n", m_serial, m_thread_request[i]);//离开临界区LeaveCriticalSection(&PC_Critical[BufferPos]);}}。

相关文档
最新文档