实验一 进程同步与互斥
进程(线程)同步和互斥实验报告
![进程(线程)同步和互斥实验报告](https://img.taocdn.com/s3/m/75ce0b60ec3a87c24128c4ac.png)
进程(线程)同步和互斥实验报告操作系统实验报告课程名称操作系统实验名称进程(线程)的同步与互斥成绩学生姓名作业君专业软件工程班级、学号同组者姓名无实验日期2021一、实验题目: : 进程(线程)的同步与互斥二、实验目的:自行编制模拟程序,通过形象化的状态显示,加深理解进程的概念、进程之间的状态转换及其所带来的 PCB 内容、组织的变化,理解进程与其 PCB 间的一一对应关系。
1.掌握基本的同步与互斥算法,理解生产者消费者模型。
2.学习使用 Windows 中基本的同步对象,掌握相关 API 的使用方法。
3.了解 Windows 中多线程的并发执行机制,实现进程的同步与互斥三、实验内容与要求:1.实验内容以生产者/消费者模型为依据,在 Windows 环境下创建一个控制台进程,在该进程中创建 n 个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
2.实验要求学习并理解生产者/消费者模型及其同步/互斥规则;学习了解 Windows 同步对象及其特性;熟悉实验环境,掌握相关 API 的使用方法;设计程序,实现生产者/消费者进程(线程)的同步与互斥;四、算法描述(含数据结构定义)或流程图#include <Windows.h> #include <iostream> #include<stdio.h> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std;#define MA__THREAD_NUM 64//最大线程数 #define INTE_PER_SEC 1000//延迟时间的毫秒值 const int SIZE_OF_BUFFER = 10;//缓冲区长度 int ProductID = 0;//产品号 int ConsumeID = 0;//将被消耗的产品号 int in = 0;//产品进缓冲区时的缓冲区下标 int out = 0;//产品出缓冲区时的缓冲区下标 bool running = true;//判断程序能否继续执行的逻辑值 intg_buffer[SIZE_OF_BUFFER];//缓冲区是个循环队列 HANDLE g_hMute_;//公有信号量,用于线程间的互斥 HANDLEg_hFullSemaphore;//生产者的私有信号量,当缓冲区满时迫使生产者等待HANDLE g_hEmptySemaphore;//消费者的私有信号量,当缓冲区空时迫使消费者等待//定义一个结构体用于存储线程的信息 struct ThreadInfo {int serial;//线程号char entity;//线程类别(生产者或消费者)double delay;//等待时间double persist; //操作时间 };//生产者 void Producer(void_p) {//定义变量用于存储当前线程的信息DWORD m_delay;DWORD m_persist;int m_serial;//从参数中获得信息m_serial = ((ThreadInfo_)(p))->serial;m_delay = (DWORD)(((ThreadInfo_)(p))->delay _INTE_PER_SEC);m_persist = (DWORD)(((ThreadInfo_)(p))->persist _INTE_PER_SEC);while (running){//P 操作cout << “生产者线程” << m_serial << “ 请求生产.” << endl;WaitForSingleObject(g_hEmptySemaphore, INFINITE);cout << “生产者线程” << m_serial << “ 请求独占缓冲区.” << endl;WaitForSingleObject(g_hMute_, INFINITE);Sleep(m_delay);//延迟等待//生产一个产品cout << “生产者线程”<< m_serial << “ 生产” << ++ProductID << “ 号产品成功.” << endl;cout << “生产者线程” << m_serial << “ 请求将产品” << ProductID << “ 投入缓冲区.” << endl;//把新生产的产品放入缓冲区g_buffer[in] = ProductID;in = (in +1)%SIZE_OF_BUFFER;Sleep(m_persist);//操作等待cout << “生产者线程” << m_serial << “ 将产品” << ProductID << “ 投入缓冲区中成功.” << endl;//输出缓冲区当前的状态cout << “____________________________” << endl<< “\n 当前缓冲区情况如图(■代表已有产品,□代表没有产品):” << endl;for (int i = 0;i < SIZE_OF_BUFFER;++i){if (g_buffer[i] != 0)cout << “■”;elsecout << “□”;}cout << “\n\n____________________________\n” << endl;//V 操作ReleaseMute_(g_hMute_);ReleaseSemaphore(g_hFullSemaphore, 1, NULL);} }//消费者 void Consumer(void_p) {DWORD m_delay;DWORD m_persist;int m_serial;//从参数中获得信息m_serial = ((ThreadInfo_)(p))->serial;m_delay = (DWORD)(((ThreadInfo_)(p))->delay _INTE_PER_SEC);m_persist = (DWORD)(((ThreadInfo_)(p))->persist _INTE_PER_SEC);while (running){//P 操作cout << “消费者线程” << m_serial << “ 请求消费.” << endl;WaitForSingleObject(g_hFullSemaphore, INFINITE);cout << “消费者线程” << m_serial << “ 请求独占缓冲区.” << endl;WaitForSingleObject(g_hMute_,INFINITE);Sleep(m_delay); //延迟等待//从缓冲区中取出一个产品cout << “消费者线程” << m_serial << “ 请求取出一个产品.” << endl;ConsumeID = g_buffer[out];g_buffer[out] = 0;out = (out + 1) % SIZE_OF_BUFFER;cout << “消费者线程” << m_serial << “ 取出产品” << ConsumeID << “ 成功.” << endl;//消耗一个产品cout << “消费者线程” << m_serial << “ 开始消费消费产品” << ConsumeID << “.” << endl;Sleep(m_persist);cout << “消费者线程” << m_serial << “ 消费产品” << ConsumeID << “ 成功.” << endl;//输出缓冲区当前的状态cout << “____________________________” << endl<< “\n 当前缓冲区情况如图:” << endl;for (int i = 0;i < SIZE_OF_BUFFER;++i){if (g_buffer[i] != 0)cout << “■”;elsecout << “□”;}cout << “\n\n____________________________\n” << endl;//V 操作ReleaseMute_(g_hMute_);ReleaseSemaphore(g_hEmptySemaphore, 1, NULL);} }void prod_cons {//创建互斥信号量g_hMute_ = CreateMute_(NULL, FALSE, NULL);//创建同步信号量g_hEmptySemaphore = CreateSemaphore(NULL,SIZE_OF_BUFFER, SIZE_OF_BUFFER, NULL);g_hFullSemaphore = CreateSemaphore(NULL, 0,SIZE_OF_BUFFER, NULL);srand((unsigned)time(NULL));//以时间函数为种子const unsigned short THREADS_COUNT = rand % 5 + 5; //总的线程数(随机生成)//线程对象的数组HANDLE hThreads[MA__THREAD_NUM];ThreadInfo thread_info[MA__THREAD_NUM];DWORD thread_ID; //线程 IDint num = 0;//临时变量,用于循环语句cout << “系统开始模拟,并自动生成模拟数据...” << endl;system(“pause”); //暂停确认开始执行cout << “线程总数:” << THREADS_COUNT << endl;//循环随机生成各个线程的信息while (num != THREADS_COUNT){thread_info[num].serial = num + 1;if (rand % 2 == 1)thread_info[num].entity = "P";elsethread_info[num].entity = "C";thread_info[num].delay = rand % 5 + 1;thread_info[num].persist = rand % 6 + 2;num++;}cout << “\n 系统生成数据结束,模拟数据如下:” << endl<< “线程号线程类别延迟时间操作时间” << endl;for (int _ = 0;_ < THREADS_COUNT;_++)cout << “” << thread_info[_].serial << “\t”<< “” << thread_info[_].entity << “\t”<< “” << thread_info[_].delay << “\t\t”<< “” << thread_info[_].persist << endl;cout << “\n\n==================生产者-消费者开始==================\n” << endl;//创建线程for (int i = 0;i < THREADS_COUNT;i++){//创建生产者线程if (thread_info[i].entity == "P")hThreads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(Producer), ;thread_info[i], 0, ;thread_ID);//创建消费者线程elsehThreads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(Consumer), ;thread_info[i], 0, ;thread_ID);}while (running){if (getchar){//按回车后终止程序运行running = false;}}cout << “系统模拟结束...” << endl; } int main {cout << “\n==================生产者-消费者模拟==================\n” << endl;prod_cons; }五、实验过程1、记录生产者和消费者的同步执行过程。
实验、进程的同步与互斥——生产者消费者
![实验、进程的同步与互斥——生产者消费者](https://img.taocdn.com/s3/m/5525dd85dc88d0d233d4b14e852458fb770b38b1.png)
实验、进程的同步与互斥——⽣产者消费者1. 1. 实验⽬的两个或两个以上的进程,不能同时进⼊关于同⼀组共享变量的临界区域,否则可能发⽣与时间有关的错误,这种现象被称作进程互斥。
对CPU的速度和数⽬不做出任何假设的前提下,并发进程互斥访问临界资源,是⼀个较好的解决⽅案。
另外,还需要解决异步环境下的进程同步问题。
所谓异步环境是指:相互合作的⼀组并发进程,其中每⼀个进程都以各⾃独⽴的、不可预知的速度向前推进;但它们⼜需要密切合作,以实现⼀个共同的任务,即彼此“知道”相互的存在和作⽤。
实验⽬的:分析进程争⽤资源的现象,学习解决进程同步与互斥的⽅法。
本实验属于设计型实验,实验者可根据⾃⾝情况选⽤合适的开发环境和程序架构。
1. 2. 实验原理信号量的PV操作与处理相关,P表⽰通过的意思,V表⽰释放的意思。
1962年,狄克斯特拉离开数学中⼼进⼊位于荷兰南部的艾恩德霍芬技术⼤学(Eindhoven Technical University)任数学教授。
在这⾥,他参加了X8计算机的开发,设计与实现了具有多道程序运⾏能⼒的操作系统——THE Multiprogramming System。
THE是艾恩德霍芬技术⼤学的荷兰⽂Tchnische Hoogeschool Eindhov –en的词头缩写。
狄克斯特拉在THE这个系统中所提出的⼀系统⽅法和技术奠定了计算机现代操作系统的基础,尤其是关于多层体系结构,顺序进程之间的同步和互斥机制这样⼀些重要的思想和概念都是狄克斯特拉在THE中⾸先提出并为以后的操作系统如UNIX等所采⽤的。
为了在单处理机的情况下确定进程(process)能否占有处理机,狄克斯特拉将每个进程分为“就绪”(ready)、“运⾏”(running)和“阻塞”(blocking)三个⼯作状态。
由于在任⼀时刻最多只有⼀个进程可以使⽤处理机,正占⽤着处理机的进程称为“运⾏”进程。
当某进程已具备了使⽤处理机的条件,⽽当前⼜没有处理机供其使⽤,则使该进程处于“就绪”状态。
实验1编程实现进程同步和互斥
![实验1编程实现进程同步和互斥](https://img.taocdn.com/s3/m/57232cbdf605cc1755270722192e453611665b65.png)
实验1编程实现进程同步和互斥进程(线程)同步和互斥是操作系统中非常重要的概念,它们用于控制多个进程(线程)之间的访问顺序,以确保数据的一致性和正确性。
在本文中,我们将详细介绍进程(线程)同步和互斥的概念,并通过编程实现来说明它们的具体应用。
1.进程(线程)同步的概念进程(线程)同步是指多个进程(线程)之间按照一定的顺序访问共享的资源,以避免竞争条件(race condition)和数据不一致的问题。
在并发环境下,多个进程(线程)同时访问共享的资源时,可能会遇到互相干扰的情况,导致程序的执行结果出现错误。
2.进程(线程)互斥的概念进程(线程)互斥是指在同一时间只能有一个进程(线程)对共享资源进行访问,其他进程(线程)必须等待当前进程(线程)释放资源后才能访问。
通过引入互斥机制,可以避免多个进程(线程)同时对共享资源进行写操作,从而保证数据的一致性和正确性。
3.进程(线程)同步和互斥的实现在实际编程中,可以通过各种同步和互斥机制来实现进程(线程)同步和互斥。
常见的机制有信号量(Semaphore)、互斥锁(Mutex)、条件变量(Condition Variable)等。
下面我们将通过一个简单的编程实例来演示如何使用信号量和互斥锁实现进程(线程)同步和互斥。
假设有两个线程,线程A负责打印奇数,线程B负责打印偶数,要求线程A和线程B交替打印1-100的数字。
我们可以使用互斥锁来控制两个线程的访问顺序,使用信号量来控制线程A和线程B的打印顺序。
首先,我们定义一个全局变量num,用来记录当前需要打印的数字。
定义一个互斥锁mutex,用来保护对num的访问。
定义一个信号量sem,用来控制线程A和线程B的打印顺序。
初始时,num为1,mutex为未锁定状态,sem的初始值为0。
线程A的处理函数如下:```void* threadA(void* arg)while (num <= 100)//等待信号量semsem_wait(&sem);//加锁pthread_mutex_lock(&mutex);//打印奇数if (num <= 100)printf("%d\n", num);num += 2;}//解锁pthread_mutex_unlock(&mutex);//发送信号量给线程Bsem_post(&sem);}return NULL;```线程B的处理函数如下:```void* threadB(void* arg)while (num <= 100)//等待信号量semsem_wait(&sem);//加锁pthread_mutex_lock(&mutex);//打印偶数if (num <= 100)printf("%d\n", num);num += 2;}//解锁pthread_mutex_unlock(&mutex);//发送信号量给线程Asem_post(&sem);}return NULL;```在主函数中创建两个线程,并执行线程:```int maipthread_t tidA, tidB;//初始化互斥锁pthread_mutex_init(&mutex, NULL);//初始化信号量sem_init(&sem, 0, 1);//创建线程Apthread_create(&tidA, NULL, threadA, NULL); //创建线程Bpthread_create(&tidB, NULL, threadB, NULL);//等待线程A结束pthread_join(tidA, NULL);//等待线程B结束pthread_join(tidB, NULL);//销毁互斥锁pthread_mutex_destroy(&mutex);//销毁信号量sem_destroy(&sem);return 0;```通过运行以上代码,我们可以看到线程A和线程B会交替打印1-100的数字,实现了进程(线程)的同步和互斥。
进程的同步与互斥实验报告
![进程的同步与互斥实验报告](https://img.taocdn.com/s3/m/1553bc231fd9ad51f01dc281e53a580216fc50fb.png)
进程的同步与互斥实验报告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.实验总结通过本次实验,我深刻理解了进程(线程)的同步与互斥,并通过实际操作加深了对这些概念的理解。
同步和互斥是操作系统中非常重要的概念,对于应对资源竞争和提高程序性能具有重要意义。
在实际开发中,我们应该合理使用同步和互斥机制,以确保程序的正确性和并发执行的效率。
操作系统实验一-进程同步
![操作系统实验一-进程同步](https://img.taocdn.com/s3/m/0de50417f12d2af90242e630.png)
实验一进程同步一、实验目的:分析进程的同步与互斥现象,编程实现经典的进程同步问题——生产者与消费者问题的模拟,进一步加深对进程同步与互斥的理解。
二、实验内容:用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](https://img.taocdn.com/s3/m/07c092d35022aaea998f0f85.png)
计算机操作系统原理实验报告专业: 110420x学号: 1104202xx姓名: xxx哈尔滨工业大学(威海)实验一进程同步和互斥一、实验目的1.掌握临界资源、临界区概念及并发进程互斥、同步访问原理。
2.学会使用高级语言进行多线程编程的方法。
3.掌握利用VC++或Java语言线程库实现线程的互斥、条件竞争,并编码实现P、V操作,利用P、V操作实现两个并发线程对有界临界区的同步访问。
4.通过该实验,学生可在源代码级完成进程同步互斥方案的分析、功能设计、编程实现,控制进程间的同步、互斥关系。
二、实验要求1.知识基础:学生应在完成进程和线程及调度等章节的学习后进行。
2.开发环境与工具:硬件平台——个人计算机。
软件平台-Windows操作系统,VC++语言或Java语言开发环境。
3.运用高级语言VC++或Java语言线程库及多线程编程技术进行设计实现。
三、实验内容1.实现临界资源、临界区、进程或线程的定义与创建。
2.利用两个并发运行的进程,实现互斥算法和有界缓冲区同步算法。
四、程序流程图1.2.生产者消费者问题生产者:消费者:五、实验结果1.互斥问题2.生产者消费者问题六、结果分析有上述程序运行结果可知,此次试验已经基本达到了实验要求,在互斥问题中,由于采用了“模拟一个竞争条件——全局变量”来建立互斥,所以不会明显的条件来判断2个线程是否正确、独立的运行,所以,在运行时间上加以限制,让2个线程在有序运行时只能持续15秒。
在生产者消费者问题中,生产者与消费者的最大上限为10,并且生产者只能生产“同一种物品”,而消费者也只能购买“同一种物品”。
操作系统实验进程同步与互斥
![操作系统实验进程同步与互斥](https://img.taocdn.com/s3/m/98ce141d3868011ca300a6c30c2259010302f37f.png)
操作系统实验进程同步与互斥操作系统实验进程同步与互斥实验目的1.掌握进程同步和互斥原理,理解生产者-消费者模型;2.学习Windows2000/xp中的多线程并发执行机制;3.学习使用Windows SDK解决读者-写者问题。
试验内容1依据生产者-消费者模型,在Windows 2000/xp环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥,分析、熟悉生产者消费者问题仿真的原理和实现技术。
(见附件2)试验内容2参考实验内容1和附件2伪码,编程解决读者-写者问题的程序。
(具体要求和读写者问题原始伪码内容见附件1)相关知识Windows 2000/XP的线程控制CreateThread完成线程创建,在调用进程的地址空间上创建一个线程,以执行指定的函数;它的返回值为所创建线程的句柄。
ExitThread用于结束当前线程。
SuspendThread可挂起指定的线程。
ResumeThread可激活指定线程,它的对应操作是递减指定线程的挂起计数,当挂起计数减为0时,线程恢复执行。
Windows 2000/XP的进程互斥和同步在Windows 2000/XP中提供了临界区、互斥对象、信号量对象同步对象和相应的系统调用,用于进程和线程同步。
临界区对象(Critical Section)只能用于在同一进程内使用的临界区,同一进程内各线程对它的访问是互斥进行的。
相关API包括:InitializeCriticalSection对临界区对象进行初始化;EnterCriticalSection等待占用临界区的使用权,得到使用权时返回;TryEnterCriticalSection非等待方式申请临界区的使用权;申请失败时,返回0;LeaveCriticalSection释放临界区的使用权;DeleteCriticalSection释放与临界区对象相关的所有系统资源。
互斥对象(Mutex)互斥对象相当于互斥信号量,在一个时刻只能被一个线程使用。
2.实验:进程的同步和互斥
![2.实验:进程的同步和互斥](https://img.taocdn.com/s3/m/784757f67c1cfad6195fa7b5.png)
《操作系统实验》
实验一:进程的同步和互斥
黄伯虎
实验内容
生产者消费者问题实现
描述:
假设存在两类进程:生产者,消费者。
它们共享n个缓冲区。
生产者行为:生产产品(每次生产1个),并将产品放入空缓冲区,循环往复,永不停息;
消费者行为:将产品从缓冲区中取出,进行消费(每次消费1个),循环往复,永不停息。
规定:缓冲区满,生产者不能放产品;缓冲区空,消费者不能取产品
要求
基本要求
实现当n=1,生产者、消费者各为1个时,同步和互斥过程
扩展要求(可选)
实现当n=c(整常数),生产者、消费者有多个(>1)时,同步和互斥过程平台和工具(原则不限,推荐如下)
Win32平台
VC++6.0
结果显示
字符界面,能说明问题即可
最终成果形式
提交实验报告1份(格式参见附件A)
报告提交时限:下一次实验开始前
提交形式:email
提交的邮件主题请按照如下格式书写:“学号+姓名+实验名称.rar/.doc”
如“030811300+张三+进程同步与互斥.rar/.doc”提交地址:
13班:xdos1@
14,31班:xdos2@。
实验一进程的同步与互斥
![实验一进程的同步与互斥](https://img.taocdn.com/s3/m/d9b1d0558762caaedc33d408.png)
实验一进程的同步与互斥一、实验目的(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;}。
操作系统实验报告——进程同步与互斥
![操作系统实验报告——进程同步与互斥](https://img.taocdn.com/s3/m/47f4f367b5daa58da0116c175f0e7cd185251871.png)
操作系统实验报告——进程同步与互斥一、实验内容本实验主要内容是通过编写程序来实现进程的同步与互斥。
具体来说,是通过使用信号量来实现不同进程之间的同步和互斥。
我们将编写两个进程,一个进程负责打印奇数,另一个进程负责打印偶数,两个进程交替打印,要求打印的数字从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,表示可以打印偶数。
操作系统实验-进程同步与互斥
![操作系统实验-进程同步与互斥](https://img.taocdn.com/s3/m/7b4c3627e97101f69e3143323968011ca300f77b.png)
操作系统实验-进程同步与互斥实验四:进程的管道通信实验题目进程的管道通信实验目的加深对进程概念的理解,明确进程和程序的区别。
学习进程创建的过程,进一步认识进程并发执行的实质。
分析进程争用资源的现象,学习解决进程互斥的方法。
学习解决进程同步的方法。
掌握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() 用于创一个子进程。
进程同步与互斥处理
![进程同步与互斥处理](https://img.taocdn.com/s3/m/976f967acaaedd3382c4d304.png)
实验题目:进程同步与互斥处理数据采集进程获取前置机传来的数据帧并存放在等待缓冲池中,如图1 所示。
等待缓冲池由10 个缓冲区组成环形队列,每个缓冲区只允许存放1 个待处理的数据帧,当缓冲池满时不允许继续存放数据帧。
数据处理进程只有在缓冲池有待处理的数据帧时才不断读取缓冲区中的数据帧,并进行处理。
一.实验要求:1)缓冲区是临界资源,写入数据帧时不能进行数据帧的读取,同时,读取数据帧时也不能进行数据帧的写入,读取/写入数据帧的时间延时可忽略不计;2)数据采集进程每次从前置机获取的数据帧大小随机产生,但不大于600Byte,两次数据采集的时间间隔为500ms(注意:在此时间间隔内不占用缓冲区);3)数据处理进程只在读取数据帧的时候占用临界资源,数据处理过程中并不占用缓冲区,数据帧的处理时间跟其大小成正比,每Byte 的处理时间为3ms。
二、概要设计1.方案分析①题目中要求缓冲区是临界资源,写入数据帧时不能进行数据帧的读取,同时,读取数据帧时也不能进行数据帧的写入,所以,数据读取和数据写入是一队互斥的进程。
因此可以定义一个互斥信号量,对其进行PV操作以实现两个进程之间互斥。
②由于题目中定义的缓冲区只能存放十个数据,一次读入只能读取一个数据,一次写入也只能一个数据,当缓冲区满了就不在写入,缓冲区空就不在读取。
为了实现其中的同步关系,我们定义两个信号量,表示缓冲区的状态,对其分别作PV操作。
2.主要功能模块的功能◆写入数据_Get进程◆读取数据和处理数据_Process 进程3.主程序的流程及各程序模块之间的层次关系◆创建Get进程、Process 进程◆控制程序运行时间◆消除进程三.详细设计1.相关进程功能◆写入数据_Get进程◆读取数据和处理数据_Process 进程2.进程间同步/互斥关系①题目中要求缓冲区是临界资源,写入数据帧时不能进行数据帧的读取,同时,读取数据帧时也不能进行数据帧的写入,所以,数据读取和数据写入是一队互斥的进程。
进程互斥与进程同步实验
![进程互斥与进程同步实验](https://img.taocdn.com/s3/m/cc5b98202f60ddccda38a00b.png)
· · · · · · · · · · · · · · · · · · · · · · · · · · sem_wait(&s_sem); /*对信号量的 P 操作*/ 临界区语句; sem_post(&full_sem); /*对信号量的 V 操作*/ · · · · · · · · · · · · · · · · · · · · · · · · · · 实例:一般情况下的生产者消费者问题 程序名:ProducerConsumer.c 程序正文:可分两种情况 (1) Linux 版本 /*多个生产者多个消费者多个缓冲区*/ #include <stdio.h> #include <stdlib.h> # include <unistd.h>*/ #include <pthread.h> #include <semaphore.h> #define M 10 /* 缓冲区数目*/ #define #define NP 6 /*生产者数目*/ NC 4 /*消费者数目*/
1 POSIX 线程编程基础
POSIX 线程模型中创建线程使用 pthread_t 变量,其步骤为: 声明:pthread_t a_thread; 创建:使用函数
int pthread_create(pthread_t *p, const pthread_attr_t *attr, void *(*start_rtn)(void),void *arg);
返回值: 如果正常创建,返回 0;否则返回一个非零的值。 第一个参数:pthread_t 变量(线程变量)的名字; 第二个参数:设置线程属性。 第三个参数:线程运行函数的起始地址(即函数名) 。 第四个参数:线程运行函数的参数。
操作系统实验报告——进程同步与互斥
![操作系统实验报告——进程同步与互斥](https://img.taocdn.com/s3/m/2a680c4c6bd97f192279e9bc.png)
《进程同步与互斥》实验报告实验序号: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)。
操作系统实训报告进程同步和互斥
![操作系统实训报告进程同步和互斥](https://img.taocdn.com/s3/m/dbcb8364ddccda38376bafe8.png)
进程同步和互斥一、设计目的:通过实现哲学家进餐问题的同步深入了解和掌握进程同步和互斥的原理。
二、设计内容哲学家有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表示该餐具当前正被使用。
计算机软件技术基础实验一进程同步与互斥
![计算机软件技术基础实验一进程同步与互斥](https://img.taocdn.com/s3/m/b5d05bf6f90f76c661371a0f.png)
计算机软件技术基础实验一姓名:张磊学号:08180214 班级:08信02班(进程同步与互斥)1、实验目的掌握基本的同步与互斥算法,理解生产者消费者模型。
2、实验要求和算法:以生产者/消费者模型为依据,创建线程模拟生产者和消费者,实现进程(线程)的同步与互斥。
算法一:(未对临界资源进行互斥访问)public class ThreadTester1 {public static void main(String[] args) {Tickets t=new Tickets(10);new Consumer(t).start();new Producer(t).start();}}class Tickets {int number=0;int size;boolean available=false;public Tickets(int size){this.size=size;}}class Producer extends Thread{Tickets t=null;public Producer(Tickets t){ this.t=t; }public void run(){while( t.number < t.size){System.out.println("Producer puts ticket "+(++t.number));t.available=true;}}}class Consumer extends Thread{Tickets t=null;int i=0;public Consumer(Tickets t){ this.t=t; }public void run(){while(i<t.size){if(t.available==true && i<=t.number)System.out.println("Consumer buys ticket "+(++i));if(i==t.number){try{ Thread.sleep(1); } catch ( InterruptedException exception ) {};t.available=false;}}}}算法2(实现了对临界资源的互斥访问)public class ThreadTester2 {public static void main(String[] args) {Tickets t=new Tickets(10);new Consumer(t).start();new Producer(t).start();}}class Tickets {int number=0;int size;boolean available=false;public Tickets(int size){{this.size=size;this.size=size;this.size=size;his.size=size;is.size=size;s.size=size;.size=size;size=size;ize=size;ze=size;e=size;=size;size;ize;ze;e;;}}}class Producer extends Thread { lass Producer extends Thread { ass Producer extends Thread { ss Producer extends Thread {s Producer extends Thread {Producer extends Thread { Producer extends Thread { roducer extends Thread {oducer extends Thread {ducer extends Thread {ucer extends Thread {cer extends Thread {er extends Thread {r extends Thread {extends Thread {extends Thread {xtends Thread {tends Thread {ends Thread {nds Thread {ds Thread {s Thread {Thread {Thread {hread {read {ead {ad {d {{{Tickets t=null;Tickets t=null;ickets t=null;ckets t=null;kets t=null;ets t=null;ts t=null;s t=null;t=null;t=null;=null;null;ull;ll;l;;public Producer(Tickets t) { this.t=t;} public Producer(Tickets t) { this.t=t;} ublic Producer(Tickets t) { this.t=t;}blic Producer(Tickets t) { this.t=t;}lic Producer(Tickets t) { this.t=t;}ic Producer(Tickets t) { this.t=t;}c Producer(Tickets t) { this.t=t;}Producer(Tickets t) { this.t=t;} Producer(Tickets t) { this.t=t;} roducer(Tickets t) { this.t=t;} oducer(Tickets t) { this.t=t;} ducer(Tickets t) { this.t=t;}ucer(Tickets t) { this.t=t;}cer(Tickets t) { this.t=t;}er(Tickets t) { this.t=t;}r(Tickets t) { this.t=t;}(Tickets t) { this.t=t;}Tickets t) { this.t=t;}ickets t) { this.t=t;}ckets t) { this.t=t;}kets t) { this.t=t;}ets t) { this.t=t;}ts t) { this.t=t;}s t) { this.t=t;}t) { this.t=t;}t) { this.t=t;}) { this.t=t;}{ this.t=t;}{ this.t=t;}this.t=t;}this.t=t;}his.t=t;}is.t=t;}s.t=t;}.t=t;}t=t;}=t;}t;};}}public void run() {public void run() {ublic void run() {blic void run() {lic void run() {ic void run() {c void run() {void run() {void run() {oid run() {id run() {d run() {run() {run() {un() {n() {() {) {{{while((t.number)<t.size) { while((t.number)<t.size) { while((t.number)<t.size) {hile((t.number)<t.size) {ile((t.number)<t.size) {le((t.number)<t.size) {e((t.number)<t.size) {((t.number)<t.size) {(t.number)<t.size) {t.number)<t.size) {.number)<t.size) {number)<t.size) {umber)<t.size) {mber)<t.size) {ber)<t.size) {er)<t.size) {r)<t.size) {)<t.size) {<t.size) {t.size) {.size) {size) {ize) {ze) {e) {) {{{synchronized(t) {synchronized(t) {synchronized(t) {synchronized(t) {synchronized(t) {synchronized(t) {synchronized(t) {ynchronized(t) {nchronized(t) {chronized(t) {hronized(t) {ronized(t) {onized(t) {nized(t) {ized(t) {zed(t) {ed(t) {d(t) {(t) {t) {) {{{System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number)); System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));System.out.println("Producer puts ticket "+(++t.number));ystem.out.println("Producer puts ticket "+(++t.number));stem.out.println("Producer puts ticket "+(++t.number));tem.out.println("Producer puts ticket "+(++t.number));em.out.println("Producer puts ticket "+(++t.number));m.out.println("Producer puts ticket "+(++t.number));.out.println("Producer puts ticket "+(++t.number));out.println("Producer puts ticket "+(++t.number));ut.println("Producer puts ticket "+(++t.number));t.println("Producer puts ticket "+(++t.number));.println("Producer puts ticket "+(++t.number));println("Producer puts ticket "+(++t.number));rintln("Producer puts ticket "+(++t.number)); intln("Producer puts ticket "+(++t.number)); ntln("Producer puts ticket "+(++t.number)); tln("Producer puts ticket "+(++t.number));ln("Producer puts ticket "+(++t.number));n("Producer puts ticket "+(++t.number)); ("Producer puts ticket "+(++t.number)); "Producer puts ticket "+(++t.number)); Producer puts ticket "+(++t.number));roducer puts ticket "+(++t.number));oducer puts ticket "+(++t.number));ducer puts ticket "+(++t.number));ucer puts ticket "+(++t.number));cer puts ticket "+(++t.number));er puts ticket "+(++t.number));r puts ticket "+(++t.number));puts ticket "+(++t.number));puts ticket "+(++t.number));uts ticket "+(++t.number));ts ticket "+(++t.number));s ticket "+(++t.number));ticket "+(++t.number));ticket "+(++t.number));icket "+(++t.number));cket "+(++t.number));ket "+(++t.number));et "+(++t.number));t "+(++t.number));"+(++t.number));"+(++t.number));+(++t.number));(++t.number));++t.number));+t.number));t.number));.number));number));umber));mber));ber));er));r));)););t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;t.available=true;.available=true;available=true;vailable=true;ailable=true;ilable=true;lable=true;able=true;ble=true;le=true;e=true;=true;true;rue;ue;e;;}}}}}}}}}}}System.out.println("Producer ends!");System.out.println("Producer ends!"); System.out.println("Producer ends!");ystem.out.println("Producer ends!");stem.out.println("Producer ends!");tem.out.println("Producer ends!");em.out.println("Producer ends!");m.out.println("Producer ends!");.out.println("Producer ends!");out.println("Producer ends!");ut.println("Producer ends!");t.println("Producer ends!");.println("Producer ends!");println("Producer ends!");rintln("Producer ends!");intln("Producer ends!");ntln("Producer ends!");tln("Producer ends!");ln("Producer ends!");n("Producer ends!");("Producer ends!");"Producer ends!");Producer ends!");roducer ends!");oducer ends!");ducer ends!");ucer ends!");cer ends!");er ends!");r ends!");ends!");ends!");nds!");ds!");s!");!");"););;}}}class Consumer extends Thread { lass Consumer extends Thread { ass Consumer extends Thread { ss Consumer extends Thread {s Consumer extends Thread {Consumer extends Thread { Consumer extends Thread { onsumer extends Thread {nsumer extends Thread {sumer extends Thread {umer extends Thread {mer extends Thread {er extends Thread {r extends Thread {extends Thread {extends Thread {xtends Thread {tends Thread {ends Thread {nds Thread {ds Thread {s Thread {Thread {Thread {hread {read {ead {ad {d {{{Tickets t=null;Tickets t=null;ickets t=null;ckets t=null;kets t=null;ets t=null;ts t=null;s t=null;t=null;t=null;=null;null;ull;ll;l;;int i=0;int i=0;nt i=0;t i=0;i=0;i=0;=0;0;;public Consumer(Tickets t) { this.t=t; } public Consumer(Tickets t) { this.t=t; } ublic Consumer(Tickets t) { this.t=t; }blic Consumer(Tickets t) { this.t=t; }lic Consumer(Tickets t) { this.t=t; }ic Consumer(Tickets t) { this.t=t; }c Consumer(Tickets t) { this.t=t; }Consumer(Tickets t) { this.t=t; }Consumer(Tickets t) { this.t=t; }onsumer(Tickets t) { this.t=t; }nsumer(Tickets t) { this.t=t; }sumer(Tickets t) { this.t=t; }umer(Tickets t) { this.t=t; }mer(Tickets t) { this.t=t; }er(Tickets t) { this.t=t; }r(Tickets t) { this.t=t; }(Tickets t) { this.t=t; }Tickets t) { this.t=t; }ickets t) { this.t=t; } ckets t) { this.t=t; } kets t) { this.t=t; } ets t) { this.t=t; }ts t) { this.t=t; }s t) { this.t=t; }t) { this.t=t; }t) { this.t=t; }) { this.t=t; }{ this.t=t; }{ this.t=t; }this.t=t; }this.t=t; }this.t=t; }this.t=t; }his.t=t; }is.t=t; }s.t=t; }.t=t; }t=t; }=t; }t; }; }}}}public void run() { public void run() {ublic void run() {blic void run() {lic void run() {ic void run() {c void run() {void run() {void run() {oid run() {id run() {d run() {run() {run() {un() {n() {() {) {{{while(i<t.size) {while(i<t.size) {while(i<t.size) {hile(i<t.size) {ile(i<t.size) {le(i<t.size) {e(i<t.size) {(i<t.size) {i<t.size) {<t.size) {t.size) {.size) {size) {ize) {ze) {e) {) {{{synchronized(t) {synchronized(t) {synchronized(t) {synchronized(t) {synchronized(t) {synchronized(t) { synchronized(t) { synchronized(t) { synchronized(t) {ynchronized(t) {nchronized(t) {chronized(t) {hronized(t) {ronized(t) {onized(t) {nized(t) {ized(t) {zed(t) {ed(t) {d(t) {(t) {t) {) {{{if(t.available==true && i<=t.number) if(t.available==true && i<=t.number) if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)if(t.available==true && i<=t.number)f(t.available==true && i<=t.number)(t.available==true && i<=t.number)t.available==true && i<=t.number).available==true && i<=t.number)available==true && i<=t.number)vailable==true && i<=t.number)ailable==true && i<=t.number)ilable==true && i<=t.number)lable==true && i<=t.number)able==true && i<=t.number)ble==true && i<=t.number)le==true && i<=t.number)e==true && i<=t.number)==true && i<=t.number)=true && i<=t.number)true && i<=t.number)rue && i<=t.number)ue && i<=t.number)e && i<=t.number)&& i<=t.number)&& i<=t.number)& i<=t.number)i<=t.number)i<=t.number)<=t.number)=t.number)t.number).number)number)umber)mber)ber)er)r))System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));System.out.println("Consumer buys ticket "+(++i));ystem.out.println("Consumer buys ticket "+(++i));stem.out.println("Consumer buys ticket "+(++i));tem.out.println("Consumer buys ticket "+(++i));em.out.println("Consumer buys ticket "+(++i));m.out.println("Consumer buys ticket "+(++i));.out.println("Consumer buys ticket "+(++i));out.println("Consumer buys ticket "+(++i));ut.println("Consumer buys ticket "+(++i));t.println("Consumer buys ticket "+(++i)); if(i==t.number) .println("Consumer buys ticket "+(++i)); if(i==t.number) println("Consumer buys ticket "+(++i)); if(i==t.number) rintln("Consumer buys ticket "+(++i)); if(i==t.number) { intln("Consumer buys ticket "+(++i)); if(i==t.number) { ntln("Consumer buys ticket "+(++i)); if(i==t.number) {tln("Consumer buys ticket "+(++i)); if(i==t.number) { ln("Consumer buys ticket "+(++i)); if(i==t.number) {n("Consumer buys ticket "+(++i)); if(i==t.number) { ("Consumer buys ticket "+(++i)); if(i==t.number) { "Consumer buys ticket "+(++i)); if(i==t.number) { Consumer buys ticket "+(++i)); if(i==t.number) { onsumer buys ticket "+(++i)); if(i==t.number) {nsumer buys ticket "+(++i)); if(i==t.number) {sumer buys ticket "+(++i)); if(i==t.number) {umer buys ticket "+(++i)); if(i==t.number) {mer buys ticket "+(++i)); if(i==t.number) {er buys ticket "+(++i)); if(i==t.number) {r buys ticket "+(++i)); if(i==t.number) {buys ticket "+(++i)); if(i==t.number) {buys ticket "+(++i)); if(i==t.number) {uys ticket "+(++i)); if(i==t.number) {ys ticket "+(++i)); if(i==t.number) {s ticket "+(++i)); if(i==t.number) {ticket "+(++i)); if(i==t.number) {ticket "+(++i)); if(i==t.number) {icket "+(++i)); if(i==t.number) {cket "+(++i)); if(i==t.number) {ket "+(++i)); if(i==t.number) {et "+(++i)); if(i==t.number) {t "+(++i)); if(i==t.number) {"+(++i)); if(i==t.number) {"+(++i)); if(i==t.number) {+(++i)); if(i==t.number) {(++i)); if(i==t.number) {++i)); if(i==t.number) {+i)); if(i==t.number) {i)); if(i==t.number) {)); if(i==t.number) {); if(i==t.number) {; if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {if(i==t.number) {f(i==t.number) {(i==t.number) {i==t.number) {==t.number) {=t.number) {t.number) {.number) {number) {umber) {mber) {ber) {er) {r) {) {{{try{Thread.sleep(1);}catch(Exception e){}t.available=false;}}}System.out.println("Consumer ends");}}4、测试结果算法一结果:Producer puts ticket 1Producer puts ticket 2Producer puts ticket 3Producer puts ticket 4Producer puts ticket 5Producer puts ticket 6Producer puts ticket 7Producer puts ticket 8Producer puts ticket 9Producer puts ticket 10算法二结果:Producer puts ticket 1Producer puts ticket 2Producer puts ticket 3Producer puts ticket 4Producer puts ticket 5Producer puts ticket 6Producer puts ticket 7Producer puts ticket 8Producer puts ticket 9Producer puts ticket 10Consumer buys ticket 1Consumer buys ticket 2Consumer buys ticket 3Consumer buys ticket 4Consumer buys ticket 5Consumer buys ticket 6Consumer buys ticket 7Consumer buys ticket 8Consumer buys ticket 9Consumer buys ticket 105、实验体会通过这次试验,我发现自己还没有完全适应这种较为复杂的算法,应多做练习,尽快适应。
实验一 进程互斥 实验报告
![实验一 进程互斥 实验报告](https://img.taocdn.com/s3/m/30dbf8d358f5f61fb7366640.png)
1.PC微机。
2.Windows操作系统。
3.C语言开发集成环境。
四、实验过程和步骤(比如流程图)
1.本实验具体要求
在同一个进程地址空间内执行的两个进程,生产者进程生产产品,然后将产品放置在一个空缓冲区中供消费者进程消费。消费者进程从缓冲区中获得产品,然后释放缓冲区。当生产者进程生产产品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者进程释放出一个空缓冲区。当消费者进程消费产品时,如果缓冲区为空,那么消费者进程将被阻塞,直到新的产品被生产出来。
计算机操作系统
模拟进程同步与互斥
注:实验报告应包含(实验目的,实验原理,主要仪器设备和材料,实验过程和步骤,实验原始数据记录和处理,实验结果和分析,成绩评定)等七项内容。具体内容可根据专业特点和实验性质略作调整,页面不够可附页。
一、实验目的
1、熟悉临界资源的、信号量及PV操作的定义
2、了解进程通信的方法
3、掌握实现进程互斥与同步的方法
4、掌握用信号量机制解决进程之间同步的与互斥的问题
5、实现生产者-消费者问题,深刻理解操作系统对进程的调度顺序及进程同步的概念
二、实验原理(主要写算法思想)
生产者-消费者问题是经典的进程同步问题,在这个问题中,生产者不断的向缓冲池中写入数据,消费者不断的从缓冲区中读取数据。生产者和消费者对缓冲池的操作是互斥的,即当前只能由一个进程对这个缓冲池进行操作。生产者生产时要判断当前缓冲池是否已满,当缓冲池满时,不能再写入,消费者消费时要判断当前缓冲池是否已空,当缓Байду номын сангаас池空时,不能再读取。
(4)当执行消费者进程时,需对产品类型进行选择,当缓冲区有该产品时,则消费者进行消费。
操作系统进程同步和互斥的实验报告
![操作系统进程同步和互斥的实验报告](https://img.taocdn.com/s3/m/76371ebf79563c1ec4da7147.png)
湖南农业大学信息科学技术学院学生实验报告【实验步骤、过程】(含原理图、流程图、关键代码,或实验过程中的记录、数据等)生产者进程(进程由多个线程组成)生产信息,例如它可以是计算进程。
消费者进程使用信息,它可以是输岀打印进程。
由于生产者和消费者彼此独立,且运行速度不确定,所以很可能岀现生产者已产生了信息而消费者却没有来得及接受信息这种情况。
为此,需要引入由一个或者若干个存储单元组成的临时存储区,以便存放生产者所产生的信息,平滑进程间由于速度不确定所带来的问题。
这个临时存储区叫做缓冲区,通常用一维数组来表示。
由一个或若干个存储单元组成的缓冲区叫作“有穷缓冲区”。
下面我们来分析一下有穷缓冲的生产者和消费者的例子。
原理图假设有多个生产者和多个消费者,它们共享一个具有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【实验结果或总结】(对实验结果进行相应分析,或总结实验的心得体会,并提出实验的改进意见)【备注】。
操作系统进程同步与互斥实验报告0204192337
![操作系统进程同步与互斥实验报告0204192337](https://img.taocdn.com/s3/m/683ba1de4afe04a1b071deaf.png)
学生实验报告姓名:年级专业班级学号成绩#define N 1 //N定义为临界资源!printf("请输入三个进程:\n"); //初始状态为:临界资源处于空闲状态!loop:scanf("%d %d %d",&a,&b,&c); //输入的进程名为:a,b,c!进程名输入的先后代表进程的访问顺序!if(a==N) //判断进程a是否占据临界资源!若a==N,表明a访问临界资源!{printf("a=%d\n",a); //a正在访问临界资源!printf("b=0,c=0\n"); //b,c不能进入自己的临界区,需等待a释放临界资源!printf(“临界资源正在被进程a访问,进程b,c必须等待.\n”);}else if(b==N){printf("b=%d\n",b); //b正在访问临界资源!printf("a=0,c=0\n"); //a,c不能进入自己的临界区,需等待b释放临界资源!printf(“临界资源正在被进程b访问,进程a,c必须等待.\n”);}5.编译链接所编写的程序,在编译正确的情况下执行程序.6.记录程序执行的结果(如下图所示).注意:初始状态为:临界资源处于空闲状20 10年12 月16 日【实验结果或总结】(对实验结果进行相应分析,或总结实验的心得体会,并提出实验的改进意见)1.进程a,b,c分别访问临界资源时程序执行的结果如下.(a) (b) (c)2.该程序初始化N为临界资源,根据输入a,b,c,的值是否等于N来判断进程分别是否进入自己的临界区。
当a=N 表明进程a正在访问临界资源。
此时程序执行的输出为:a=1,b=c=0表示进程b,c不能进入自己的临界区。
3.该程序能较好地体现程序并发执行时的一种制约关系-互斥,但不能较好的反映进程的同步关系,所以该算法有待改进,用以同时实现进程的同步和互斥。
进程同步互斥1
![进程同步互斥1](https://img.taocdn.com/s3/m/43185d24f011f18583d049649b6648d7c1c708e5.png)
进程同步互斥1进程的同步互斥实验实验⽬的1、进⼀步认识并发执⾏的实质2、分析进程竞争资源的现象,学习解决进程同步互斥的⽅法实验内容1、编写程序,使⽤相关函数实现⽗⼦进程对共享⽂件的同步互斥访问。
2、修改程序,观察对临界资源访问的互斥控制的作⽤。
实验基础⼀、临界资源的互斥访问为了实现多进程对临界资源的互斥访问,⼀个进程访问临界资源的典型程序段类似如下形式:{ ……….进⼊区临界区;退出区其余代码;………}其中,进⼊区中判断资源是否可⽤,如果可⽤,则资源数量减1,进程进⼊临界区;否则进程阻塞等待。
退出区中资源数量加1,唤醒阻塞等待该资源的进程。
进⼊区和退出区都是原⼦操作。
操作系统中,通常⽤信号量来实现进⼊区和退出区,即P操作和V操作。
为了实现⽤户程序中对某些资源的同步互斥访问,操作系统也提供了⼀些函数接⼝,功能类似于对特定临界区的进⼊区和退出区功能。
⼆、相关的系统调⽤(1)lockf(files,function,size) :⽤作锁定⽂件的某些段或者整个⽂件。
函数原型:#includeint lockf(int files,int function;long size)其中:files是⽂件描述符;参数function可以取以下值:F_LOCK:锁定⼀个区域。
F_ULOCK:解除锁定。
参数size指明了从⽂件当前位置开始的⼀段连续锁定区域的长度,当size为0时,锁定记录将由当前位置⼀直扩展到⽂件尾。
如果lockf的参数function取值为F_LOCK,⽽指定⽂件的对应区域已被其他进程锁定,那么lockf的调⽤进程将被阻塞直到该区域解锁。
通过使⽤lockf函数,可实现多进程对共享⽂件进⾏互斥访问。
进程的实现中,必须使得每个进程在使⽤⽂件前对⽂件加锁,使⽤⽂件后解锁。
(2)open:打开⼀个⽂件函数原型:#include#include#includeint open(char *path,int flags,mode_t mode);其中:参数path 是指向所要打开的⽂件的路径名指针。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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]; //缓冲区声明 HANDLEh_Thread[MAX_THREAD_NUM]; //存储线程句柄的数组ThreadInfoThread_info[MAX_THREAD_NUM]; //线程信息数组 HANDLEempty_semephore; //信号量 HANDLE h_mutex; //互斥量 DWORD n_Thread=0; //实际线程数目 DWORD n_Buffer_or_Critical; //实际缓冲区/临界区数目HANDLE h_semephore[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;ifstream inFile;//初始化缓冲区for(int i=0;i<MAX_BUFFER_NUM;i++)Buffer_Critical[i]=-1;//初始化各线程的请求队列for(int j=0;j<MAX_THREAD_NUM;j++){ for(int k=0;j<MAX_THREAD_NUM;k++)Threa_Info[j].thread_request[k]=1;Thread_Info[j].n_request=0;}//初始化临界区对象for(int i=0;i<MAX_BUFFER_NUM;i++)InitializeCriticalSection(&PC_Critical[i]);//打开输入文件,提取线程信息inFile.open(“test.txt”);//从文件中获得实际缓冲区数目inFile>>n_Buffer_or_Critical;inFile.get();printf(“输入文件是:\n”);//回显获得的缓冲区数目printf(“%d \n”,(int)n_Buffer_or_Critical);//提取各线程信息到相应的数据结构中while(inFile){ inFile>>Thread_Info[n_Thread].serial;inFile>>Thread_Info[n_Thread].entity;inFile>>Thread_Info[n_Thread].delay;char c;inFile.get(c);while(c!=’\n’&&!inFile.eof()){ inFile>>Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_request ++];inFile.get(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_In[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 atposition %2d.\n”,m_seri al,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*))->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 re quest to consume %2dproduct\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 %2dproduct\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);}else{printf(“Consumer %2d finish consuming product %2d\n”,m_serial,m_thread_request[i]);}//离开临界区LeaveCriticalSection(&PC_Critical[BufferPos]); }}。