操作系统实验--进程的同步heu
- 格式:doc
- 大小:6.90 MB
- 文档页数:13
操作系统中的进程同步与互斥进程同步和互斥是操作系统中重要的概念和技术。
在多道程序环境中,多个进程同时运行,但它们之间存在着共享资源、互相依赖等情况,因此需要进行同步和互斥处理。
本文将从互斥与同步的定义、需求、常用的同步与互斥机制等方面进行论述。
一、互斥与同步的定义互斥是指某个资源同时只允许一个进程访问,其他进程需要等待。
同步是指一组相关进程在执行过程中需要相互合作,按照一定顺序执行。
二、互斥与同步的需求1. 互斥:当多个进程同时访问一个共享资源时,若不进行互斥处理,可能会引发数据不一致、竞争条件等问题。
例如,多个进程同时对一个文件进行写操作,可能导致文件内容错乱。
因此,需要通过互斥来保证每个进程访问共享资源的独占性,避免冲突。
2. 同步:在某些情况下,多个进程需要按照一定顺序执行,以满足某种逻辑关系或条件。
例如,生产者-消费者问题中,生产者需要在缓冲区未满时才能生产,消费者需要在缓冲区非空时才能消费。
因此,需要通过同步来协调进程的执行顺序。
三、常用的同步与互斥机制1. 互斥机制:常用的互斥机制包括信号量、互斥锁和临界区等。
a) 信号量:是一种用于控制对共享资源的访问的机制。
通过定义一个信号量,以保证同一时间只有一个进程可以访问共享资源。
典型的信号量包括二进制信号量和计数信号量。
b) 互斥锁:是一种用于协调多个进程访问共享资源的机制。
通过对共享资源加锁,只有持有锁的进程才能访问该资源,其他进程需要等待。
常见的互斥锁有互斥量(Mutex)和读写锁(ReadWrite Lock)等。
c) 临界区:是指一段在并发执行环境中,对某种共享资源进行操作的代码段。
在进入临界区之前,进程需要获取临界区的访问权限,执行完临界区代码后,释放访问权限。
通过临界区机制,可以保证同一时间只有一个进程在执行临界区的代码。
2. 同步机制:常用的同步机制包括信号量、条件变量和屏障等。
a) 信号量:除了用于互斥机制,信号量也可以用于同步机制。
进程的同步与互斥实验报告1.实验目的进程(线程)的同步与互斥是操作系统中非常重要的概念,本实验旨在通过实际操作,加深对这些概念的理解和掌握。
通过编写多个进程(线程),并在其间进行同步与互斥操作,验证同步与互斥的实际效果。
2.实验环境本实验在Linux系统下进行,使用C/C++语言编程。
3.实验内容3.1同步在实验中,我们编写了两个进程A和B,这两个进程需要按照特定的顺序执行。
为了实现同步,我们使用信号量机制来确保进程A和B按照正确的顺序执行。
3.2互斥在实验中,我们编写了多个进程C和D,这些进程需要同时对一个共享资源进行访问。
为了实现互斥,我们使用互斥锁机制来确保同一时刻只有一个进程访问共享资源。
4.实验过程4.1同步实验编写进程A和进程B的代码,使用信号量机制实现同步。
进程A先运行,然后通过信号量唤醒进程B,进程B再开始执行。
通过观察进程的运行顺序,验证同步机制是否起作用。
4.2互斥实验编写进程C和进程D的代码,使用互斥锁机制实现互斥。
进程C和进程D同时对一个共享资源进行访问,通过互斥锁来确保同一时刻只有一个进程访问共享资源。
观察进程的输出结果,验证互斥机制是否起作用。
5.实验结果5.1同步实验结果进程A开始执行进程A执行完毕进程B开始执行进程B执行完毕5.2互斥实验结果进程C开始执行进程C访问共享资源进程C执行完毕进程D开始执行进程D访问共享资源进程D执行完毕6.实验分析通过上述结果可以看出,同步实验中进程A和进程B按照正确的顺序执行,证明了同步机制的有效性。
互斥实验中进程C和进程D能够正确地交替访问共享资源,证明了互斥机制的有效性。
7.实验总结通过本次实验,我深刻理解了进程(线程)的同步与互斥,并通过实际操作加深了对这些概念的理解。
同步和互斥是操作系统中非常重要的概念,对于应对资源竞争和提高程序性能具有重要意义。
在实际开发中,我们应该合理使用同步和互斥机制,以确保程序的正确性和并发执行的效率。
实验一进程同步一、实验目的:分析进程的同步与互斥现象,编程实现经典的进程同步问题——生产者与消费者问题的模拟,进一步加深对进程同步与互斥的理解。
二、实验内容:用C语言实现对生产者与消费者问题的模拟。
实验原理:生产者和消费者是经典的进程同步问题,在这个问题中,生产者不断的向缓冲区中写入数据,而消费者则从缓冲区中读取数据。
生产者进程和消费者对缓冲区的操作是互斥,即当前只能有一个进程对这个缓冲区进行操作,生产者进入操作缓冲区之前,先要看缓冲区是否已满,如果缓冲区已满,则它必须等待消费者进程将数据取出才能写入数据,同样的,消费者进程从缓冲区读取数据之前,也要判断缓冲区是否为空,如果为空,则必须等待生产者进程写入数据才能读取数据。
三、实验准备:1. 实现步骤:(1)分析计算机系统中对资源的分配与释放过程:计算机系统中的每个进程都可以消费或生产某类资源。
当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。
而当某个进程释放资源时,则它就相当一个生产者。
(2)定义生产者消费者问题中的各数据结构,并初始化信号量;(3)创建生产者与消费者进程,利用信号量实现生产者与消费者之间的同步与互斥;最后编程实现。
2. 相关函数:在实现的过程中需要用到以下API函数:(1)CreateThread()//该函数创建一个在调用进程的地址空间中执行的线程。
若线程创建成功,将返回该线程的句柄。
函数原型:HANDLE CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes, //描述安全性,用NULL表示使用缺省值DWORD dwStackSize, //新线程拥有自己的堆栈,0表示使用缺省值1MB,推荐LPTHREAD_START_ROUTINE lpStartAddress, //新线程的起始地址,放线程函数名称LPVOID lpParameter,//此值被传送到线程函数去作为参数DWORD dwCreationFlags,//允许产生一个暂时挂起的线程,默认是0立即开始执行LPDWORD lpThreadld );//新线程的ID被传到这用法举例:hHandle1 = CreateThread( (LPSECURITY_ATTRIBUTES) NULL,0,(LPTHREAD_START_ROUTINE) ThreadName1,(LPVOID) NULL,0, &dwThreadID1 );(2)CreateMutex()函数可用来创建一个有名或无名的互斥量对象,函数返回值为互斥对象的句柄。
操作系统中的进程同步与互斥实现在操作系统中,进程同步和互斥是非常重要的概念。
进程同步是确保多个进程在共享资源时按照特定的顺序进行访问,而互斥是确保在任何时候只能有一个进程访问共享资源。
本文将介绍进程同步和互斥的操作系统机制,并讨论它们在现代操作系统中的应用。
一、进程同步机制实际应用场景中,许多进程都需要共享某些资源。
在这种情况下,同步机制可以确保按照特定的顺序共享资源,以避免竞争和死锁。
1.信号量信号量是最常见的同步机制之一。
在操作系统中,信号量是一个计数器,用于记录共享资源的使用次数。
当进程需要访问资源时,它会尝试获取信号量。
如果资源当前没有被其他进程使用,信号量的值将减去1,并且进程将可以访问资源。
如果资源已经被其他进程使用,进程将被阻塞,直到资源可用。
当进程完成资源的使用时,它必须释放信号量,使其值增加1,以便其他进程可以访问该资源。
2.互斥锁互斥锁是一种更简单和更常见的同步机制,它用于确保共享资源仅由一个进程使用。
在操作系统中,互斥锁是一种执行阻塞锁的特殊锁。
如果一个进程想要访问一个共享资源,它必须先尝试获取互斥锁。
如果锁当前未被其他进程使用,则该进程将能够访问资源,锁将被锁定,以允许进程在访问资源时保持独占状态。
当进程完成访问资源时,它必须释放该锁,以便其他进程可以使用它。
3.条件变量条件变量是一种同步机制,用于仅在特定条件下执行操作。
条件变量由两个主要部分组成:条件和等待队列。
条件是一个布尔表达式,用于检查是否满足特定的条件。
等待队列是队列,其中包含在条件不满足时被阻塞的进程。
当条件被满足时,等待进程将被唤醒,并且可以开始执行所需的操作。
二、进程互斥机制在共享资源时,进程互斥是非常重要的。
这可以确保在任何时候仅有一个进程访问共享资源。
以下是三种常见的互斥机制的例子:1.临界区临界区是指只能由一个进程访问的代码部分。
在这种情况下,进程将在进入临界区之前获得互斥锁,以确保在任何时候只有一个进程可以访问临界区。
一、实验目的1. 理解进程同步的概念和原理;2. 掌握进程同步的基本方法和机制;3. 学会使用信号量实现进程同步;4. 通过实验验证进程同步机制的有效性。
二、实验原理1. 进程同步:在多道程序设计中,进程的执行是并发的,但某些情况下需要保证多个进程按照一定的顺序执行,以避免出现数据不一致、死锁等问题。
进程同步是指通过某种机制,协调多个进程的执行顺序,保证它们能够正确、有效地共享资源。
2. 信号量:信号量是一种特殊的变量,用于实现进程同步。
信号量具有两个原子操作:P操作(wait)和V操作(signal)。
P操作用于申请资源,V操作用于释放资源。
3. 互斥锁:互斥锁是一种常见的进程同步机制,用于保证临界资源的互斥访问。
当一个进程进入临界区时,它会尝试获取互斥锁,如果锁已被其他进程获取,则该进程进入等待状态;当进程退出临界区时,它会释放互斥锁。
三、实验内容1. 实验环境:Linux操作系统,C语言编程环境。
2. 实验工具:gcc编译器、gdb调试器。
3. 实验步骤:(1)创建一个互斥锁,用于保护临界资源。
(2)编写两个进程,分别模拟对临界资源的访问。
(3)在进程访问临界资源前,使用P操作尝试获取互斥锁。
(4)在进程访问临界资源后,使用V操作释放互斥锁。
(5)编译并运行程序,观察进程执行情况。
四、实验结果与分析1. 实验结果:(1)在互斥锁的保护下,两个进程能够按照预期顺序访问临界资源。
(2)当其中一个进程正在访问临界资源时,另一个进程会进入等待状态。
(3)当进程访问临界资源完成后,它会释放互斥锁,允许其他进程访问。
2. 实验分析:(1)互斥锁能够有效地保护临界资源,避免数据不一致问题。
(2)信号量P操作和V操作保证了进程的同步,避免了死锁现象。
(3)通过实验验证了进程同步机制的有效性。
五、实验总结本次实验通过使用信号量和互斥锁,实现了进程同步。
实验结果表明,信号量和互斥锁能够有效地保证进程按照预期顺序执行,避免数据不一致和死锁等问题。
操作系统中进程同步和互斥的实现方法在操作系统中,进程同步和互斥是非常重要的概念。
它们确保了并发程序的正确性和可靠性。
本文将介绍进程同步和互斥的实现方法。
一、进程同步在多任务环境中,不同的进程之间存在着相互依赖和相互制约的关系。
进程同步是为了协调进程之间的交互,使得它们在适当的时间进行合作,共同完成任务。
1. 互斥锁(Mutex)互斥锁是最常见的进程同步机制之一。
它通过给临界资源加锁,保证同一时刻只有一个进程可以访问该资源。
当一个进程占用了互斥锁后,其他进程试图访问该资源时会被阻塞,直到锁被释放。
2. 信号量(Semaphore)信号量是一种更加通用的进程同步机制。
它是一个计数器,用来控制多个进程对共享资源的访问。
当信号量的值大于等于1时,进程可以访问资源;当值为0时,进程被阻塞。
通过对信号量的操作(P/V操作),可以实现进程之间的同步和互斥。
3. 条件变量(Condition Variable)条件变量用于实现进程间的同步和通信。
当一个进程等待某个条件满足时,可以调用条件变量的等待操作来挂起它的执行;当条件满足时,其他进程可以通过唤醒操作通知等待的进程继续执行。
二、进程互斥进程互斥是为了防止多个进程同时访问或修改共享资源而引发的竞争条件和数据不一致问题。
它保证了同一时刻只有一个进程可以对共享资源进行操作,从而避免了竞争和冲突。
1. 临界区(Critical Section)临界区是一段代码,其中包含对共享资源的访问和操作。
为了实现进程的互斥访问,可以使用互斥锁、信号量等同步机制来对临界区进行保护。
一次只允许一个进程进入临界区,其他进程必须等待。
2. Peterson算法Peterson算法是一种经典的实现进程互斥的算法。
它利用了共享的标志和转弯顺序来实现两个进程之间的互斥访问。
然而,Peterson算法只适用于两个进程之间的互斥,对于多个进程之间的互斥并不适用。
3. 同步屏障(Barrier)同步屏障是一种常用的进程互斥机制。
0711操作系统进程调度和进程同步实验要求实验内容:用线程模拟进程,实现进程调度和进程同步。
在任意操作系统中,用c、c++或者java 编写程序。
并且完成相应的实验报告。
实验要求:实验一:进程调度⑴ 主线程,创建子线程,保存子线程的虚拟PCB(参见恐龙书P74)、要求运行多少时间(可随机产生)、已经等待多少时间(初始化为0),优先级(可随机产生)等信息,并负责子线程的调度。
调度的基本时间单位为1 S。
⑵ 创建20个线程(可以只用一个线程函数,传递不同的参数即上述数据结构)分别实现FCFS调度、SJF调度、RR调度、优先级调度和多级队列调度,并且计算每个调度的平均等待时间。
其中,多级队列调度要求设计4个调度队列,每个队列5个线程,队列内部分别采用FCFS、SJF、RR和优先级调度。
时间片的长度可以随机生成为n S。
⑶ 对于每个子线程,在其运行期间,输出其占用的时间标号(例如,第3个线程占用了第10秒的CPU时间,输出为:“Thread 3: 10”,格式可自行设计)。
实验二:进程同步⑴ 模拟哲学家就餐问题:设置5个子线程模拟5个哲学家,设置5个互斥区为筷子。
⑵ 输出问题解决方法:在每个哲学家线程中输出其获得的筷子标号与时间(可以读取系统时间,或者自行设置时间标准),例如:哲学家2在第n秒获得筷子1,在第m秒获得筷子2。
实验报告要求:写明实验目的、实验设计步骤、实验结果、总结。
附录:windows线程基本操作以windows线程函数为例介绍线程基本操作,以下函数都必须包含windows.h头文。
如果想更深入地了解线程,请参见《c++编程艺术》等相关书籍。
线程创建函数:HANDLE CreateThread (LPSECURITY_ATTRIBUTES secAttr,SIZE_T stackSize,LPTHREAD_START_ROUTINE threadFunc,LPVOID param,DWORD flags,LPDWORD threadID);在此,secAttr是一个用来描述线程的安全属性的指针。
操作系统的进程同步与互斥操作系统是计算机系统中最核心的组成部分之一,它负责管理计算机资源和协调各个应用程序的执行。
在多任务处理的环境下,不同的进程可能会同时访问共享资源,为了保证数据的一致性和避免竞争条件的出现,操作系统引入了进程同步与互斥机制。
本文将深入探讨操作系统中进程同步与互斥的原理和实现方式。
一、进程的概念和特点进程是操作系统中的基本执行单元,它是一个正在执行中的程序的实例。
进程是临时的,动态的,具有独立的内存空间和执行环境,通过操作系统的调度器来进行管理和调度。
每个进程都有自己的执行序列,独立的内存空间和上下文环境。
进程的特点包括:并发性、独立性、异步性和共享性。
并发性指的是多个进程可以同时存在于内存中,并且可以以任意的次序进行执行。
独立性体现在每个进程都拥有独立的执行序列和内存空间,彼此之间不会相互影响。
异步性是指进程的执行是由操作系统的调度器决定的,进程之间的执行顺序是不可预测的。
共享性是指多个进程可以同时访问和共享系统资源。
二、进程同步的概念和原因进程同步是指进程之间按照一定的规定,按照一定的次序来访问和使用共享资源的过程。
在多个进程同时访问共享资源的情况下,如果没有进行进程同步,就会导致数据的不一致性和竞争条件的发生。
因此,进程同步是操作系统必须解决的一个重要问题。
进程同步的原因主要有以下几点:互斥访问资源、合作共享资源、数据的一致性和死锁的避免。
互斥访问资源是指多个进程需要对共享资源进行访问时,要求只有一个进程可以访问该资源,其他进程必须等待。
合作共享资源是指多个进程之间需要协同工作,共同完成某个任务,如生产者-消费者问题。
数据的一致性要求多个进程在访问和修改数据时能够保持数据的正确性和完整性。
死锁是指进程之间因为争夺资源而相互等待,导致系统无法继续运行。
三、进程同步与互斥的实现方式为了实现进程同步与互斥,操作系统提供了一些机制和算法。
其中比较常用的有:临界区、互斥量、信号量和条件变量。
操作系统实验报告——进程同步与互斥一、实验内容本实验主要内容是通过编写程序来实现进程的同步与互斥。
具体来说,是通过使用信号量来实现不同进程之间的同步和互斥。
我们将编写两个进程,一个进程负责打印奇数,另一个进程负责打印偶数,两个进程交替打印,要求打印的数字从1开始,直到100结束。
二、实验原理进程的同步是指多个进程之间按照一定的顺序执行,进程之间互相等待的关系。
而进程的互斥是指多个进程竞争同一个资源,需要通过其中一种方式来避免同时访问共享资源,以免造成数据错乱。
在本实验中,我们使用信号量来实现进程的同步与互斥。
信号量是一个计数器,用于表示一些共享资源的可用数量。
进程在访问共享资源时,需要先对信号量进行操作,当信号量大于0时,表示资源可用,进程可以访问;当信号量等于0时,表示资源不可用,进程需要等待。
进程同步的实现可以通过信号量的P操作与V操作来完成。
P操作用于申请资源,当资源可用时,将计数器减一,并进入临界区;V操作用于释放资源,当资源使用完毕时,将计数器加一,使等待资源的进程能够申请。
进程互斥的实现可以通过信号量的P操作与V操作结合临界区来完成。
当多个进程需要访问共享资源时,需要先进行P操作,进入临界区,访问完毕后进行V操作,离开临界区。
三、实验步骤1.首先,我们需要创建两个进程,一个进程负责打印奇数,另一个进程负责打印偶数。
2. 然后,我们创建一个共享变量count,用来记录打印的数字。
3. 接着,我们创建两个信号量odd和even,用来控制进程的同步与互斥。
odd信号量初始值为1,表示打印奇数的进程可以访问;even信号量初始值为0,表示打印偶数的进程需要等待。
4.编写奇数打印进程的代码,首先进行P操作,判断奇数信号量是否大于0,如果大于0,表示可以打印奇数。
5. 如果可以打印奇数,将count加一,并输出当前的奇数,然后进行V操作,释放偶数打印进程的等待。
6.同样的,编写偶数打印进程的代码,首先进行P操作,判断偶数信号量是否大于0,如果大于0,表示可以打印偶数。
进程的同步实验报告进程的同步实验报告引言:进程同步是操作系统中一个重要的概念,它涉及到多个进程之间的协调和合作。
在本次实验中,我们将通过一个简单的实例来探讨进程同步的概念和实现方式。
实验目的:通过实验,我们的目标是理解进程同步的概念,学习常见的同步机制,并通过编程实现一个简单的同步问题。
实验环境:本次实验使用了C语言作为编程语言,并在Linux操作系统上进行。
实验过程:我们的实验场景是一个餐厅,有一个厨师和多个服务员。
厨师负责烹饪菜品,服务员负责上菜给客人。
我们需要实现的是,服务员只有在厨师烹饪好一道菜之后才能上菜,否则需要等待。
首先,我们使用互斥锁来实现进程间的同步。
互斥锁是一种常见的同步机制,它可以确保在同一时间只有一个进程可以访问共享资源。
在我们的实验中,厨师和服务员都需要访问菜品资源,因此我们为菜品资源添加了一个互斥锁。
接下来,我们使用条件变量来实现进程间的等待和唤醒操作。
条件变量是一种同步机制,它可以让进程在某个条件满足时等待,直到被唤醒。
在我们的实验中,服务员需要等待厨师烹饪好菜品之后才能上菜,因此我们创建了一个条件变量,并在服务员的代码中使用了等待和唤醒操作。
实验结果:经过实验,我们成功地实现了进程间的同步。
在我们的实验场景中,厨师会不断地烹饪菜品,并在烹饪完成后通知服务员上菜。
服务员会等待厨师的通知,然后上菜给客人。
通过互斥锁和条件变量的使用,我们保证了服务员只会在厨师烹饪完成后才会上菜,避免了资源竞争和错误的上菜行为。
讨论与总结:通过本次实验,我们深入理解了进程同步的概念和实现方式。
互斥锁和条件变量是常见的同步机制,它们可以有效地解决进程间的竞争和协调问题。
在实际的操作系统中,进程同步是一个非常重要的概念,它保证了多个进程之间的正确执行和合作。
然而,进程同步也可能引发一些问题。
例如,如果互斥锁的使用不当,可能会导致死锁的发生。
死锁是一种进程无法继续执行的状态,它会导致系统的停滞。
1.实验内容(进程的同步)(1)阅读理解示例程序。
(2)说明示例程序是否能适合解决N个生产者和1个消费者问题,并设计实验验证(3) 参照教材修改为N个生产者和1个消费者问题(4) 思考N个生产者和M个消费者问题的解决方案(不要求)(5) 利用信号量解决同步问题。
2.实验目的通过程序模拟及验证生产者消费者问题等经典问题,深入理解并发中的同步和互斥的概念3.实验原理(1)进程概念:(1.定义:程序的一次执行过程(2.三种基本状态:就绪状态,执行状态,阻塞状态(2)进程同步:(1.定义:并发进程在执行次序上的协调,以达到有效的资源共享和相互合作,使程序执行有可再现性。
(2.两种形式的制约关系:(一:资源共享关系:进程间接制约,需互斥地访问临界资源。
)、(二:相互合作关系:进程直接制约)(3.临界资源:一次仅允许一个进程访问的资源,引起不可再现性是因为临界资源没有互斥访问。
(3)信号量:定义一个用于表示资源数目的整型量S,它与一般的整型量不同,除初始化外,仅能通过两个标准的原子操作wait(S)和signal(S)来访问,俗称P,V操作。
通俗来讲就是用P来访问资源后减去一个单位资源,用V操作来释放一个单位资源就是现有资源上加一个单位资源。
4.实验内容一:说明示例程序是否能适合解决N个生产者和1个消费者问题,并设计实验验证答:示例程序不能解决多个生产者和消费者的问题,它是解决单个消费者和生产者的。
如果可以就要修改代码,如“二”所说。
二:多个消费者和生产者的问题如上图所示:如果要解决多个生产者和消费者的问题:第一步:分析上图得出了两种关系,分别是异步和同步的关系第二步:异步关系的是生产者和生产者之间的,因为同一时刻只能有一个生产者访问缓冲区,所以我们就可以设置临界资源.获得临界资源的生产者才能把产品放到缓冲区里第三步:同步关系有两个,首先是生产者和缓冲区之间,再是缓冲区和消费者之间。
他们都满足一前一后的关系,即当缓冲区空间未满时,生产者才可以放产品;缓冲区不为空的时候才可以让消费者取出产品消费。
操作系统实验-进程同步与互斥实验四:进程的管道通信实验题目进程的管道通信实验目的加深对进程概念的理解,明确进程和程序的区别。
学习进程创建的过程,进一步认识进程并发执行的实质。
分析进程争用资源的现象,学习解决进程互斥的方法。
学习解决进程同步的方法。
掌握Linux系统中进程间通过管道通信的具体实现实验内容使用系统调用pipe()建立一条管道,系统调用fork()分别创建两个子进程,它们分别向管道写一句话,如:Child process1 is sending a message!Child process2 is sending a message!父进程分别从管道读出来自两个子进程的信息,显示在屏幕上。
当然,仅仅通过屏幕上输出这两句话还不能说明实现了进程的管道通信,为了能够更好的证明和显示出进程的同步互斥和通信,在其中要加入必要的跟踪条件,如一定的输出语句等,来反映程序的并发执行情况实验要求这是一个设计型实验,要求自行、独立编制程序。
两个子进程要并发执行。
实现管道的互斥使用。
当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。
使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定。
实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
为了清楚的反应进程的同步,在子进程完成相应的操作后,调用sleep()函数睡眠一段时间(程序中定为3s)。
父进程先执行wait()函数,当有子进程执行完毕后,会得到子进程的返回结果并清理子进程。
若子进程没执行完,父进程一直执行wait()进行监听,知道有一个子进程执行完成为僵尸进程。
程序中用到的系统调用因为程序时在linux系统上进行编写的,所以其中要利用到相关的linux提供的系统调用。
所用到的系统调用包含在如下头文件中。
#include#include#include#include#include#includefork() 用于创一个子进程。
操作系统实验报告工程大学计算机科学与技术学院页脚.第六讲进程的同步一、实验概述1. 实验名称进程的同步2. 实验目的(1)使用EOS 的信号量编程解决生产者—消费者问题,理解进程同步的意义。
(2)调试跟踪EOS 的信号量的工作过程,理解进程同步的原理。
(3)修改EOS 的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。
3. 实验类型验证型实验,设计性实验4. 实验容(1)准备实验(2)使用 EOS 的信号量解决生产者-消费者问题(3)调试 EOS 信号量的工作过程1)创建信号量2)等待释放信号量3)等待信号量(不阻塞)4)释放信号量(不唤醒)5) 等待信号量(阻塞)6) 释放信号量(唤醒)(4)修改 EOS 的信号量算法二、实验环境操作系统集成实验环境OS Lab三、实验过程1. 设计思路和流程图2. 算法实现3. 需要解决的问题及解答(1). P143生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?生产者和消费者是怎样使用同步对象来实现该同步过程的呢?答:此时生产了0-13号14个产品,消费了0-3号4个产品,缓冲区都占满了。
只有缓冲区有空闲生产者才能生产东西,有权向里面放东西。
所以它必须等到消费者,取走产品,有空闲缓冲区时,才继续生产14号产品。
(2). P145-3.4 修改EOS的信号量算法(只看一次消费1个产品的,一次消费2个产品的可以写到实验报告中)答:见三,四部分(3). 思考在ps/semaphore.c文件的PsWaitForSemaphore和PsReleaseSemaphore函数中,为什么要使用原子操作?答:原子操作要求一旦开始就要运行到结束,不能有中断。
在执行等待信号量和释放信号量的时候,不允许cpu响应外部中断,所以使用原子操作。
(4). 绘制ps/semaphore.c文件PsWaitForSemaphore和PsReleaseSemaphore函数的流程图。
计算机操作系统中的进程同步和互斥机制计算机操作系统中的进程同步和互斥机制是保证多个进程能够正确共享资源和互相协调工作的重要方法。
进程同步和互斥机制可以防止多个进程在并发执行时产生冲突、竞争条件和不一致性问题。
本文将介绍进程同步机制和互斥机制的定义、作用以及常见的实现方式。
一、进程同步机制进程同步是指多个进程在执行过程中按一定的规则进行协作,以达到资源共享和顺序访问的目的。
进程同步机制的作用是确保共享资源不会被并发进程同时访问和修改,避免数据的错误和不一致性。
1. 信号量信号量是一种经典的进程同步机制,它可以用来同步进程的执行顺序和限制进程对共享资源的访问。
信号量可以分为二进制信号量和计数信号量两种类型。
二进制信号量只有两个取值,用于实现互斥访问共享资源;计数信号量可以有多个取值,用于实现进程之间的同步。
2. 互斥量互斥量是一种特殊的二进制信号量,用于保护共享资源的互斥访问。
每次只允许一个进程访问共享资源,其他进程需要等待互斥量释放后才能进行访问。
互斥量可以通过上锁(lock)和解锁(unlock)操作实现。
3. 条件变量条件变量是一种线程同步的高级机制,用于在多个线程之间进行通信和协调,实现某个条件的等待和唤醒。
条件变量通常和互斥量一起使用,通过等待和唤醒的方式实现线程之间的同步。
二、进程互斥机制进程互斥是指多个进程在访问共享资源时需要互斥进行,确保在同一时间只有一个进程可以访问共享资源,避免数据的冲突和不一致性。
1. 临界区临界区是指一段代码片段,同一时间只允许一个进程或线程执行。
进程在进入临界区之前需要获得锁,执行完临界区代码后释放锁,其他进程才能进入临界区。
2. 互斥锁互斥锁是一种基于互斥量实现的进程互斥机制,用于保护共享资源的互斥访问。
每次只允许一个进程获取互斥锁,其他进程需要等待互斥锁释放才能继续执行。
3. 读写锁读写锁是一种特殊的互斥锁,用于在读操作和写操作之间进行互斥。
读操作之间不互斥,写操作和读操作之间互斥,写操作之间互斥。
实验三进程的同步一、实验目的1、了解进程同步和互斥的概念及实现方法;2、更深一步的了解fork()的系统调用方式。
二、实验内容1、预习操作系统进程同步的概念及实现方法。
2、编写一段源程序,用系统调用fork()创建两个子进程,当此程序运行时,在系统中有一个父进程和两个子进程活动。
让每一个进程在屏幕上显示一个字符:父进程显示字符“a”;子进程分别显示字符“b”和字符“c”。
程序的输出是什么?分析原因。
3、阅读模拟火车站售票系统和实现进程的管道通信源代码,查阅有关进程创建、进程互斥、进程同步的系统功能调用或API,简要解释例程中用到的系统功能或API的用法,并编辑、编译、运行程序,记录程序的运行结果,尝试给出合理的解释。
4、(选做)修改问题2的代码,使得父子按顺序显示字符“a”;“b”、“c”编辑、编译、运行。
记录程序运行结果。
三、设计思想1、程序框架(1)创建两个子进程:(2)售票系统:(3)管道通信:先创建子进程,然后对内容加锁,将输出语句存入缓存,并让子进程自己进入睡眠,等待别的进程将其唤醒,最后解锁;第二个子进程也执行这样的过程。
父进程等待子进程后读内容并输出。
(4)修改程序(1):在子进程的输出语句前加上sleep()语句,即等待父进程执行完以后再输出。
2、用到的文件系统调用函数(1)创建两个子进程:fork()(2)售票系统:DWORD WINAPI Fun1Proc(LPVOID lpPartameter);CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);CloseHandle(hThread1);(HANDLE)CreateMutex(NULL,FALSE,NULL);Sleep(4000)(sleep调用进程进入睡眠状态(封锁), 直到被唤醒);WaitForSingleObject(hMutex,INFINITE);ReleaseMutex(hMutex);(3)管道通信:pipe(fd),fd: int fd[2],其中: fd[0] 、fd[1]文件描述符(读、写);lockf( fd,function,byte)(fd: 文件描述符;function: 1: 锁定 0:解锁;byte: 锁定的字节数,0: 从当前位置到文件尾);write(fd,buf,byte)、read(fd,buf,byte) (fd: 文件描述符;buf : 信息传送的源(目标)地址;byte: 传送的字节数);sleep(5);exit(0);read(fd[0],s,50)(4)修改程序(1):fork(); sleep();四、调试过程1、测试数据设计(1)创建两个子进程:运行结果:(2)售票系统:运行结果:(3)管道通信:运行结果:(4)修改程序(1):2、测试结果分析 (1)调用fork()创建一个子进程,当运行到第一个子进程输出了b ,当父进程运行时创建另一个子进程。
实验三:进程同步实验一、实验任务:(1)掌握操作系统的进程同步原理;(2)熟悉linux的进程同步原语;(3)设计程序,实现经典进程同步问题。
二、实验原理:(1)P、V操作PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:P(S):①将信号量S的值减1,即S=S-1;②如果S³0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S):①将信号量S的值加1,即S=S+1;②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
(2)信号量信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。
信号量的值与相应资源的使用情况有关。
当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。
注意,信号量的值仅能由PV操作来改变。
一般来说,信号量S³0时,S表示可用资源的数量。
执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。
而执行一个V操作意味着释放一个单位资源,因此S 的值加1;若S£0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。
(3)linux的进程同步原语①wait();阻塞父进程,子进程执行;②#include <sys/types.h>#include <sys/ipc.h>key_t ftok (char*pathname, char proj);它返回与路径pathname相对应的一个键值。
③int semget(key_t key, int nsems, int semflg)参数key是一个键值,由ftok获得,唯一标识一个信号灯集,用法与msgget()中的key 相同;参数nsems指定打开或者新创建的信号灯集中将包含信号灯的数目;semflg参数是一些标志位。
《进程同步与互斥》实验报告实验序号:01 实验项目名称:进程同步与互斥学号姓名专业、班实验地点指导教师时间一、实验目的1、掌握基本的进程同步与互斥算法,理解生产者-消费者问题。
2、学习使用Windows 2000/XP中基本的同步对象,掌握相关API的使用方法。
3、了解Windows 2000/XP中多线程的并发执行机制,实现进程的同步与互斥。
4、设计程序,实现生产者-消费者进程(线程)的同步与互斥;二、实验环境Windows 2000/XP + Visual C++ 6.0三、实验内容以生产者-消费者模型为依据,在Windows 2000/XP环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
四、设计思路和流程框图生产者进程的功能:生产东西,供消费者消费;消费者进程的功能:消费生产者生产的东西。
生产者生产产品并存入缓冲区供消费者取走使用,消费者从缓冲器内取出产品去消费。
在生产者和消费者同时工作时,必须禁止生产者将产品放入已装满的缓冲器内,禁止消费者从空缓冲器内取产品。
五、源程序(含注释)清单#include<windows.h>printf("Consumer %2d finish consuming product %2d\n ",m_serial,m_thread_request[i]);}//离开临界区LeaveCriticalSection(&PC_Critical[BufferPos]);}}六、测试结果以及实验总结1、通过实验进一步了解了基本的进程同步与互斥算法,理解生产者-消费者问题2、掌握了相关API的使用方法。
3、了解到进程是一个可以拥有资源的基本单位,是一个可以独立调度和分派的基本单位。
而线程是进程中的一个实体,是被系统独立调度和分配的基本单位,故又称为轻权(轻型)进程(Light Weight Process)。
进程同步和互斥一、设计目的:通过实现哲学家进餐问题的同步深入了解和掌握进程同步和互斥的原理。
二、设计内容哲学家有N个,也定全体到达后开始讨论:在讨论的间隙哲学家进餐,每人进餐时都需使用刀、叉各一把,所有哲学家刀和叉都拿到后才能进餐。
哲学家的人数、餐桌上的布置自行设定,实现刀和叉的互斥使用算法的程序实现。
三、开发环境windows环境,VC6.0平台。
四、分析设计<一>实验原理不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
每个进程中访问临界资源的那段代码称为临界区(Critical Section)。
每个进程中访问临界资源的那段程序称为临界区(Critical Section)(临界资源是一次仅允许一个进程使用的共享资源)。
每次只准许一个进程进入临界区,进入后不允许其他进程进入。
不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
本程序主要使用了EnterCriticalSection (&cs)和LeaveCriticalSection (&cs)两个函数实现临界区互斥。
EnterCriticalSection (&cs)用来进入临界区,LeaveCriticalSection (&cs)用来离开临界区。
哲学家进餐问题设定图<二>程序结构1、主程序模块(详见图1)2、状态改变模块(详见图2)3、返回哲学家状态模块(详见图3)4、返回餐具状态模块(详见图4)<三>数据结构:程序中定义一个哲学家类,包含两个私有对象和四个公有对象。
Number对象:报讯哲学家的编号。
Status对象:用于保存当前该哲学家的状态,0表示正在等待(即处于饥饿状态)1表示得到餐具正在吃饭,2表示正在思考Philosopher(int num)方法:哲学家类构造函数,参数num表示哲学家编号find() const方法:返回该哲学家编号getinfo() const方法:返回哲学家当前状态Change()方法:根据题目要求改变哲学家的状态(等待->进餐->思考->等待…………)另外,程序中包含一个公有对象,bool类型数组tools[6],用来保存6把餐当前状态:true 表示该餐具当前空闲,false表示该餐具当前正被使用。
湖南农业大学信息科学技术学院学生实验报告【实验步骤、过程】(含原理图、流程图、关键代码,或实验过程中的记录、数据等)生产者进程(进程由多个线程组成)生产信息,例如它可以是计算进程。
消费者进程使用信息,它可以是输岀打印进程。
由于生产者和消费者彼此独立,且运行速度不确定,所以很可能岀现生产者已产生了信息而消费者却没有来得及接受信息这种情况。
为此,需要引入由一个或者若干个存储单元组成的临时存储区,以便存放生产者所产生的信息,平滑进程间由于速度不确定所带来的问题。
这个临时存储区叫做缓冲区,通常用一维数组来表示。
由一个或若干个存储单元组成的缓冲区叫作“有穷缓冲区”。
下面我们来分析一下有穷缓冲的生产者和消费者的例子。
原理图假设有多个生产者和多个消费者,它们共享一个具有n个存储单元的有穷缓冲区Buffer(O .... n -1),这是一个环形队列。
其队尾指针Rear指向当前信息应存放的位置(Buffer[Rear]),队首指针Front指向当前取出信息的位置(Buffer[front])。
生产者进程总是把信息存放在Buffer[Rear]中,消费者进程则总是从Buffer [Rear] 中取出信息。
如果想使生产者进程和消费者进程协调合作,则必须使它们遵循如下规则:1)只要缓冲区有存储单元,生产者都可往其中存放信息;当缓冲区已满时,若任意生产者提岀写要求,则都必须等待;2)只要缓冲区中有消息可取,消费者都可从缓冲区中取岀消息;当缓冲区为空时,若任意消费者想取岀信息,则必须等待;3)生产者们和消费者们不能同时读、写缓冲区。
流程图代码:public class ProducerC on sumer { public static void main( Str in g[] args) { Syn cStack ss = new Syn cStack(); Producer p = new Producer(ss);Con sumer c = new Con sumer(ss); new Thread(p).start();new Thread(p).start();new Thread(p).start();new Thread(c).start();}}class WoTou {int id;WoTou(i nt id) {=id;}public Stri ng toStri ng() {return "WoTou :" + id;}}class Syn cStack {int in dex = 0;WoTo u[] arrWT = new WoTou[6];public syn chr oni zed void push(WoTou wt) { while(i ndex == {try {();} catch (In terruptedExcepti on e) {();}}();arrWT[i ndex] = wt;in dex ++;}public syn chr oni zed WoTou pop() { while(i ndex == 0) {try {();} catch (In terruptedExcepti on e) {();}}();in dex--;retur n arrWT[i ndex];}}class Producer impleme nts Runn able { Syn cStack ss = n ull;Producers yn cStack ss) {=ss;}public void run() {for(i nt i=0; i<20; i++) {WoTou wt = new WoTou(i);(wt);"生产了:“ + wt);try {((in t)() * 200));} catch (In terruptedExcepti on e) {();}}}}class Con sumer impleme nts Runn able { Syn cStack ss = n ull;Con sumer(S yn cStack ss) {=ss;}public void run() {for(i nt i=0; i<20; i++) {WoTou wt =();"消费了:" + wt);try {((in t)() * 1000));} catch (In terruptedExcepti on e) {();}}}}结果:(随机的)生产了:WoTou : 0生产了:WoTou : 0 消费了:WoTou:0生产了:WoTou: 1 生产了:WoTou: 1 生产了:WoTou: 1 生产了:WoTou:2 生产了:WoTou : 3 消费了:WoTou : 2 消费了:WoTou:3生产了:WoTou : 4 消费了:WoTou : 4 生产了:WoTou:5 消费了:WoTou:5生产了:WoTou : 6 消费了:WoTou : 6 生产了:WoTou:2 消费了:WoTou:2生产了:WoTou : 3 消费了:WoTou : 3 生产了:WoTou:4 消费了:WoTou:4生产了:WoTou : 5 消费了:WoTou : 5 生产了:WoTou:6消费了:WoTou:6【实验结果或总结】(对实验结果进行相应分析,或总结实验的心得体会,并提出实验的改进意见)【备注】。
操作系统进程同步实验报告本实验旨在通过模拟操作系统中进程的同步问题,加深学生对操作系统中进程同步机制的了解和实践能力。
本次实验分为两个部分,第一个部分是使用信号量实现进程同步,第二个部分是使用管程实现进程同步。
第一部分实验:使用信号量实现进程同步本部分实验的目标是使用信号量来实现进程同步,确保资源的互斥访问。
在Linux系统中,信号量是一种用来控制进程同步的机制,可以用于保证共享资源的互斥访问、避免死锁等问题。
具体实验流程如下:1. 定义一个信号量,用于互斥访问共享资源在Linux系统中,使用semget函数可以创建一个信号量集,使用semctl函数可以对信号量进行控制。
```#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#define KEY 1234 // 定义信号量的键值int semid; // 定义信号量标识符union semun{int val; // 信号量的初始值struct semid_ds *buf; // IPC_STAT, IPC_SET操作时用ushort *array; // GETALL, SETALL操作时用};void init_sem(){int ret;union semun semunion;// 创建信号量semid = semget(KEY, 1, IPC_CREAT | 0666);if(semid == -1){perror("semget error");exit(1);}2. 定义生产者和消费者进程,并使用信号量来实现同步在生产者和消费者进程中,需要先对信号量进行P操作,即申请资源,然后进行对共享资源的操作,最后再对信号量进行V操作,即释放资源。
本实验中,共享资源是一个循环缓冲区,生产者进程向其中写入数据,消费者进程从中读取数据。
操作系统实验报告哈尔滨工程大学计算机科学与技术学院第六讲进程的同步一、实验概述1. 实验名称进程的同步2. 实验目的(1)使用EOS 的信号量编程解决生产者—消费者问题,理解进程同步的意义。
(2)调试跟踪EOS 的信号量的工作过程,理解进程同步的原理。
(3)修改EOS 的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。
3. 实验类型验证型实验,设计性实验4. 实验内容(1)准备实验(2)使用 EOS 的信号量解决生产者-消费者问题(3)调试 EOS 信号量的工作过程1)创建信号量2)等待释放信号量3)等待信号量(不阻塞)4)释放信号量(不唤醒)5) 等待信号量(阻塞)6) 释放信号量(唤醒)(4)修改 EOS 的信号量算法二、实验环境操作系统集成实验环境OS Lab三、实验过程1. 设计思路和流程图2. 算法实现3. 需要解决的问题及解答(1). P143生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢生产者和消费者是怎样使用同步对象来实现该同步过程的呢答:此时生产了0-13号14个产品,消费了0-3号4个产品,缓冲区都占满了。
只有缓冲区有空闲生产者才能生产东西,有权向里面放东西。
所以它必须等到消费者,取走产品,有空闲缓冲区时,才继续生产14号产品。
(2). 修改EOS的信号量算法(只看一次消费1个产品的,一次消费2个产品的可以写到实验报告中)答:见三,四部分(3). 思考在ps/文件内的PsWaitForSemaphore和PsReleaseSemaphore函数中,为什么要使用原子操作答:原子操作要求一旦开始就要运行到结束,不能有中断。
在执行等待信号量和释放信号量的时候,不允许cpu响应外部中断,所以使用原子操作。
(4). 绘制ps/文件内PsWaitForSemaphore和PsReleaseSemaphore函数的流程图。
PsWaitForSemaphorePs Release Semaphore原子操作前关中断开始原子操作P操作P操作结束Wait操作的信号量大于0Y执行P操作N4. 主要数据结构、实现代码及其说明1)修改PsWaitForSemaphore函数if (Semaphore->Count>0){Semaphore->Count--;flag=STATUS_SUCCESS;}源程序并附上注释#include ""VOIDPsInitializeSemaphore(IN PSEMAPHORE Semaphore,IN LONG InitialCount,IN LONG MaximumCount)/*++功能描述:初始化信号量结构体。
参数:Semaphore -- 要初始化的信号量结构体指针。
InitialCount -- 信号量的初始值,不能小于0 且不能大于MaximumCount。
MaximumCount -- 信号量的最大值,必须大于0。
返回值:无。
--*/{ASSERT(InitialCount >= 0 && InitialCount <= MaximumCount && MaximumCount > 0);Semaphore->Count = InitialCount;Semaphore->MaximumCount = MaximumCount;ListInitializeHead(&Semaphore->WaitListHead);}STATUSPsWaitForSemaphore(IN PSEMAPHORE Semaphore,IN INT Milliseconds,IN STATUS i)/*++功能描述:信号量的Wait 操作(P 操作)。
参数:Semaphore -- Wait 操作的信号量对象。
Milliseconds -- 等待超时上限,单位毫秒。
返回值:STATUS_SUCCESS。
当你修改信号量使之支持超时唤醒功能后,如果等待超时,应该返回STA TUS_TIMEOUT。
--*/{BOOL IntState;ASSERT(KeGetIntNesting() == 0); 程序运行时的初值和运行结果(1)准备实验1)启动 OS Lab。
2)新建一个 EOS Kernel 项目。
3)生成 EOS Kernel 项目,从而在该项目文件夹中生成 SDK 文件夹。
4)新建一个 EOS 应用程序项目。
5)使用在第 3 步生成的 SDK 文件夹覆盖 EOS 应用程序项目文件夹中的 SDK 文件夹。
(2)使用EOS的信号量解决生产者-消费者问题1)使用文件中的源代码,替换之前创建的 EOS 应用程序项目中文件内的源代码。
2)按 F7 生成修改后的 EOS 应用程序项目。
3)按 F5 启动调试。
OS Lab 会首先弹出一个调试异常对话框。
4)在调试异常对话框中选择“否”,继续执行。
5)立即激活虚拟机窗口查看生产者-消费者同步执行的过程。
6)待应用程序执行完毕后,结束此次调试。
(3)调试EOS信号量的工作过程1)创建信号量○1按 F5 启动调试 EOS 应用项目。
OS Lab 会首先弹出一个调试异常对话框。
○2在调试异常对话框中选择“是”,调试会中断。
○3在 main 函数中创建 Empty 信号量的代码行(第 77 行)EmptySemaphoreHandle = CreateSemaphore(BUFFER_SIZE, BUFFER_SIZE, NULL); 添加一个断点。
○4按 F5 继续调试,到此断点处中断。
○5按 F11 调试进入 CreateSemaphore 函数。
可以看到此 API 函数只是调用了 EOS 内核中的PsCreateSemaphoreObject 函数来创建信号量对象。
○6按 F11 调试进入文件中的 PsCreateSemaphoreObject 函数。
在此函数中,会在 EOS内核管理的内存中创建一个信号量对象(分配一块内存),而初始化信号量对象中各个成员的操作是在PsInitializeSemaphore 函数中完成的。
○7在文件的顶部查找到 PsInitializeSemaphore 函数的定义(第 19 行),在此函数的第一行(第39 行)代码处添加一个断点。
○8按 F5 继续调试,到断点处中断。
观察 PsInitializeSemaphore 函数中用来初始化信号量结构体成员的值,应该和传入 CreateSemaphore 函数的参数值是一致的。
○9按 F10 单步调试 PsInitializeSemaphore 函数执行的过程,查看信号量结构体被初始化的过程。
打开“调用堆栈”窗口,查看函数的调用层次。
2)等待信号量(不阻塞)○1删除所有的断点(防止有些断点影响后面的调试)。
○2在文件的 Producer 函数中,等待 Empty 信号量的代码行(第 144 行)WaitForSingleObject(EmptySemaphoreHandle, INFINITE); 添加一个断点。
○3按 F5 继续调试,到断点处中断。
○WaitForSingleObject 函数最终会调用内核中的 PsWaitForSemaphore 函数完成等待操作。
所以,在文件中 PsWaitForSemaphore 函数的第一行(第 68 行)添加一个断点。
○5按 F5 继续调试,到断点处中断。
○6按 F10 单步调试,直到完成 PsWaitForSemaphore 函数中的所有操作。
可以看到此次执行并没有进行等待,只是将 Empty 信号量的计数减少了 1(由 10 变为了 9)就返回了。
3)释放信号量(不唤醒)○1删除所有的断点(防止有些断点影响后面的调试)。
○2在文件的 Producer 函数中,释放 Full 信号量的代码行(第 152 行)ReleaseSemaphore(FullSemaphoreHandle, 1, NULL); 添加一个断点。
○3按 F5 继续调试,到断点处中断。
○4按 F11 调试进入 ReleaseSemaphore 函数。
○5继续按 F11 调试进入 PsReleaseSemaphoreObject 函数。
○6先使用 F10 单步调试,当黄色箭头指向第 269 行时使用 F11 单步调试,进入PsReleaseSemaphore函数。
○7按 F10 单步调试,直到完成 PsReleaseSemaphore 函数中的所有操作。
可以看到此次执行没有唤醒其它线程(因为此时没有线程在 Full 信号量上被阻塞),只是将 Full 信号量的计数增加了 1(由 0 变为了 1)。
4)等待信号量(阻塞)○1结束之前的调试。
○2删除所有的断点。
○3按 F5 重新启动调试。
OS Lab 会首先弹出一个调试异常对话框。
○4在调试异常对话框中选择“是”,调试会中断。
○5在文件中的 PsWaitForSemaphore 函数的PspWait(&Semaphore->WaitListHead, INFINITE); 代码行(第 78 行)添加一个断点。
○6按 F5 继续调试,并立即激活虚拟机窗口查看输出。
开始时生产者、消费者都不会被信号量阻塞,同步执行一段时间后才在断点处中断。
○7中断后,查看“调用堆栈”窗口,有 Producer 函数对应的堆栈帧,说明此次调用是从生产者线程函数进入的。
○8在“调用堆栈”窗口中双击 Producer 函数所在的堆栈帧,绿色箭头指向等待 Empty 信号量的代码行,查看 Producer 函数中变量 i 的值为 14,表示生产者线程正在尝试生产 14 号产品。
○在“调用堆栈”窗口中双击 PsWaitForSemaphore 函数的堆栈帧,查看 Empty 信号量计数(Semaphore->Count)的值为-1,所以会调用 PspWait 函数将生产者线程放入 Empty 信号量的等待队列中进行等待(让出 CPU)。
○激活虚拟机窗口查看输出的结果。
生产了从 0 到 13 的 14 个产品,但是只消费了从 0 到 3 的 4 个产品,所以缓冲池中的 10 个缓冲区就都被占用了,这与之前调试的结果是一致的。
5)释放信号量(唤醒)○1删除所有断点。
○2在文件的 Consumer 函数中,释放 Empty 信号量的代码行(第 180 行)ReleaseSemaphore(EmptySemaphoreHandle, 1, NULL); 添加一个断点。