实验二(1)进程同步

实验二(1)进程同步
实验二(1)进程同步

实验二(2)进程同步

一、实验目的

1、生产者-消费者问题是很经典很具有代表性的进程同步问题,计算机中的很多同步问题都可抽象为生产者-消费者问题,通过本实验的练习,希望能加深学生对进程同步问题的认识与理解。

2、熟悉VC的使用,培养和提高学生的分析问题、解决问题的能力。

二、实验内容及其要求

1.实验内容

以生产者/消费者模型为依据,创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。

2.实验要求

学习并理解生产者/消费者模型及其同步/互斥规则;设计程序,实现生产者/消费者进程(线程)的同步与互斥;

三、实验算法分析

1、实验程序的结构图(流程图);

2、数据结构及信号量定义的说明;

(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);

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

●参数说明

lpMutexAttributes——必须取值NULL。上加锁)。

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——指向临界区对象的指针

4、主要算法

创建生产者和消费者线程

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);

else

h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume),

&(Thread_Info[i]),0,NULL);

}

生产者进程

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_thread_request[i] = ((ThreadInfo*)(p))->thread_request[i];

Sleep(m_delay);

//循环进行所需产品的消费

for(i =0;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 consume %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);

}

else{

printf("Consumer %2d finish consuming product %2d\n ",m_serial,m_thread_request[i]);

}

//离开临界区

LeaveCriticalSection(&PC_Critical[BufferPos]);

}

}

示例程序源代码:

#include

#include

#include

#include

#include

//定义常量;

//此程序允许的最大临界区数;

#define MAX_BUFFER_NUM 10

//秒到微秒的乘法因子;

#define INTE_PER_SEC 1000

//本程序允许的生产和消费线程的总数;

#define MAX_THREAD_NUM 64

//定义一个结构,记录在测试文件中指定的每一个线程的参数

struct ThreadInfo

{

int serial; //线程序列号

char entity; //是P还是C

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 FindProducePositon();

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

for(int k=0;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.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

printf(" %d ", Thread_Info[j].thread_request[k]);

cout<

}

printf("\n\n");

//创建在模拟过程中几个必要的信号量

empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical,

"semaphore_for_empty");

h_mutex = CreateMutex(NULL,FALSE,"mutex_for_update");

//下面这个循环用线程的ID号来为相应生产线程的产品读写时所

//使用的同步信号量命名;

for(j=0;j<(int)n_Thread;j++){

std::string lp ="semaphore_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);

else

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");

getch();

return 0;

}

//确认是否还有对同一产品的消费请求未执行;

bool IfInOtherRequest(int req)

{

for(int i=0;i

for(int j=0;j

if(Thread_Info[i].thread_request[j] == req)

return TRUE;

return FALSE;

}

//找出当前可以进行产品生产的空缓冲区位置;

int FindProducePosition()

{

int EmptyPosition;

for (int i =0;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

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_thread_request[i] = ((ThreadInfo*)(p))->thread_request[i];

Sleep(m_delay);

//循环进行所需产品的消费

for(i =0;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 consume %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);

}

else{

printf("Consumer %2d finish consuming product %2d\n ",m_serial,m_thread_request[i]);

}

//离开临界区

LeaveCriticalSection(&PC_Critical[BufferPos]);

}

}

实验二(1)进程同步

实验二(2)进程同步 一、实验目的 1、生产者-消费者问题是很经典很具有代表性的进程同步问题,计算机中的很多同步问题都可抽象为生产者-消费者问题,通过本实验的练习,希望能加深学生对进程同步问题的认识与理解。 2、熟悉VC的使用,培养和提高学生的分析问题、解决问题的能力。 二、实验内容及其要求 1.实验内容 以生产者/消费者模型为依据,创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。 2.实验要求 学习并理解生产者/消费者模型及其同步/互斥规则;设计程序,实现生产者/消费者进程(线程)的同步与互斥; 三、实验算法分析 1、实验程序的结构图(流程图); 2、数据结构及信号量定义的说明; (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); bInitialOwner——指示当前线程是否马上拥有该互斥量(即马 ●参数说明 lpMutexAttributes——必须取值NULL。上加锁)。 lpName——互斥量名称。 (3) CreateSemaphore ●功能——创建一个命名或匿名的信号量对象 ●格式 HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName ); ●参数说明 lpSemaphoreAttributes——必须取值NULL。

操作系统进程同步实验报告

实验三:进程同步实验 一、实验任务: (1)掌握操作系统的进程同步原理; (2)熟悉linux的进程同步原语; (3 )设计程序,实现经典进程同步问题。 二、实验原理: (1)P、V操作 PV操作由P操作原语和V操作原语组成(原语是不可中断的过程) ,对信号量进行操作,具体定义如下: P( S):①将信- 号量S的值减1,即S=S-1; ②如果S30,则该进程继续执行;否则该进程置为等待状态,排入等待队列。 V( S):①将信号量S的值加1,即S=S+1 ; ②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。 (2)信号量 信号量(semaphore )的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的 值仅能由PV操作来改变。 一般来说,信号量S30时,S表示可用资源的数量。执行一次P操作意味着请求分配一 个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S 的值加1;若S均,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。 (3)linux的进程同步原语 ①wait();阻塞父进程,子进程执行; ②#in clude #in clude key_t ftok (char*path name, char proj) ;它返回与路径path name 相对应的一个键值。 ③int semget(key_t key, int n sems, int semflg) 参数key是一个键值,由ftok获得,唯一标识一个信号灯集,用法与msgget()中的key 相同;参数nsems指定打开或者新创建的信号灯集中将包含信号灯的数目;semflg参数是一些标志位。参数key和semflg的取值,以及何时打开已有信号灯集或者创建一个新的信号灯集与msgget()中的对应部分相同。该调用返回与健值key相对应的信号灯集描述字。调用返回:成功返回信号灯集描述字,否则返回-1。 ④int semop(i nt semid, struct sembuf *sops, un sig ned n sops); semid是信号灯集ID , sops指向数组的每一个sembuf结构都刻画一个在特定信号灯上的操作。nsops为sops指向数组的大小。 ⑤int semctl(int semid , int semnum , int cmd , union semun arg) 该系统调用实现对信号灯的各种控制操作,参数semid指定信号灯集,参数cmd指定 具体的操作类型;参数semnum指定对哪个信号灯操作,只对几个特殊的cmd操作有意义;

实验二--单处理器系统的进程调度

实验二单处理器系统的进程调度 (附实验报告) 1.实验目的 加深对进程概念的理解,明确进程和程序的区别; 深入了解系统如何组织进程、创建进程; 进一步认识如何实现处理器调度。 2.实验预备知识 进程的概念; 进程的组织方式; 进程的创建; 进程的调度。 3.实验内容

编写程序完成单处理机系统中的进程调度,要求采用时间片轮转调度算法。实验具体包括:首先确定进程控制块的内容,进程控制块的组成方式;然后完成进程创建原语和进程调度原语;最后编写主函数对所作工作进程测试。 4.提示与讲解 这个实验主要要考虑三个问题:如何组织进程、如何创建进程和如何实现处理器调度。 考虑如何组织进程,首先就要设定进程控制块的内容。进程控制块PCB 记录各个进程执行时的情况。不同的操作系统,进程控制块记录的信息内容不一样。操作系统功能越强,软件也越庞大,进程控制块记录的内容也就越多。这里的实验只使用了必不可少的信息。一般操作系统中,无论进程控制块中信息量多少,信息都可以大致分为以下四类: ①标识信息 每个进程都要有一个惟一的标识符,用来标识进程的存在和区别于其他进程。这个标识符是必不可少的,可以用符号或编号实现,它必须是操作系统分配的。在后面给出的参考程序中,采用编号方式,也就是为每个进程依次分配一个不相同的正整数。 ②说明信息

用于记录进程的基本情况,例如进程的状态、等待原因、进程程序存放位置、进程数据存放位置等等。实验中,因为进程没有数据和程序,仅使用进程控制块模拟进程,所以这部分内容仅包括进程状态。 ③现场信息 现场信息记录各个寄存器的内容。当进程由于某种原因让出处理器时,需要将现场信息记录在进程控制块中,当进行进程调度时,从选中进程的进程控制块中读取现场信息进行现场恢复。现场信息就是处理器的相关寄存器内容,包括通用寄存器、程序计数器和程序状态字寄存器等。在实验中,可选取几个寄存器作为代表。用大写的全局变量AX、BX、CX、DX模拟通用寄存器、大写的全局变量PC模拟程序计数器、大写的全局变量PSW模拟程序状态字寄存器。 ④管理信息 管理信息记录进程管理和调度的信息。例如进程优先数、进程队列指针等。实验中,仅包括队列指针。 因此可将进程控制块结构定义如下: struct pcb {int name; int status;

os实验二 进程同步

实验二:进程同步 一.实验目的 (1)掌握基本的同步算法,理解生产者消费者模型。 (2)学习使用Windows XP中基本的同步对象,掌握相关API的使用方法。 (3)了解Windows XP中多线程的并发执行机制,实现进程的同步与互斥。 二.实验属性 该实验为设计性实验。 三.实验仪器设备及器材 普通PC386以上微机 四.实验要求 本实验要求2学时完成。 本实验要求完成如下任务: (1)以生产者/消费者模型为依据,在Windows XP环境下创建一个控制台进程,在该进程中创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥。 学习并理解生产者/消费者模型及其同步/互斥规则; 学习了解Windows同步对象及其特性; 熟悉实验环境,掌握相关API的使用方法; 设计程序,实现生产者/消费者进程(线程)的同步与互斥。 (2)扩展任务2选1: 1>利用信号量机制,写出不会发生死锁的解决哲学家进程(线程)。 最多允许4个同时进餐;奇:先左后右偶:先右后左。 2>利用信号量机制,写出不会发生死锁的读者写者进程(线程)。五:实验内容: 利用至多同时允许4位哲学家同时去拿左边筷子的方法解决进餐死锁的问题。 实验详细设计:流程图:

程序首先创建一个线程参数结构体 struct ThreadInfo { int serial; double delay; }; 设置最多同时去拿筷子的人数#define MAX_BUFFER_NUM 4 设置一个信号量数组用来表示五位哲学家的左右边的筷子HANDLE chopstick [5]; 设置同时去拿筷子的人数的信号量HANDLE People; 设置一个互斥信号量HANDLE h_mutex; 在main()函数中,首先创建信号量: for (int i=0;i<5;i++) { chopstick[i]=CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Criti cal,"chopstick"+i); } People=CreateSemaphore(NULL,MAX_BUFFER_NUM,MAX_BUFFER _NUM,"People");

操作系统实验报告--实验一--进程管理

实验一进程管理 一、目的 进程调度是处理机管理的核心内容。本实验要求编写和调试一个简单的进程调度程序。通过本实验加深理解有关进程控制块、进程队列的概念,并体会和了解进程调度算法的具体实施办法。 二、实验内容及要求 1、设计进程控制块PCB的结构(PCB结构通常包括以下信息:进程名(进程ID)、进程优先数、轮转时间片、进程所占用的CPU时间、进程的状态、当前队列指针等。可根据实验的不同,PCB结构的内容可以作适当的增删)。为了便于处理,程序中的某进程运行时间以时间片为单位计算。各进程的轮转时间数以及进程需运行的时间片数的初始值均由用户给定。 2、系统资源(r1…r w),共有w类,每类数目为r1…r w。随机产生n进程P i(id,s(j,k),t),0<=i<=n,0<=j<=m,0<=k<=dt为总运行时间,在运行过程中,会随机申请新的资源。 3、每个进程可有三个状态(即就绪状态W、运行状态R、等待或阻塞状态B),并假设初始状态为就绪状态。建立进程就绪队列。 4、编制进程调度算法:时间片轮转调度算法 本程序用该算法对n个进程进行调度,进程每执行一次,CPU时间片数加1,进程还需要的时间片数减1。在调度算法中,采用固定时间片(即:每执行一次进程,该进程的执行时间片数为已执行了1个单位),这时,CPU时间片数加1,进程还需要的时间片数减1,并排列到就绪队列的尾上。 三、实验环境 操作系统环境:Windows系统。 编程语言:C#。 四、实验思路和设计 1、程序流程图

2、主要程序代码 //PCB结构体 struct pcb { public int id; //进程ID public int ra; //所需资源A的数量 public int rb; //所需资源B的数量 public int rc; //所需资源C的数量 public int ntime; //所需的时间片个数 public int rtime; //已经运行的时间片个数 public char state; //进程状态,W(等待)、R(运行)、B(阻塞) //public int next; } ArrayList hready = new ArrayList(); ArrayList hblock = new ArrayList(); Random random = new Random(); //ArrayList p = new ArrayList(); int m, n, r, a,a1, b,b1, c,c1, h = 0, i = 1, time1Inteval;//m为要模拟的进程个数,n为初始化进程个数 //r为可随机产生的进程数(r=m-n) //a,b,c分别为A,B,C三类资源的总量 //i为进城计数,i=1…n //h为运行的时间片次数,time1Inteval为时间片大小(毫秒) //对进程进行初始化,建立就绪数组、阻塞数组。 public void input()//对进程进行初始化,建立就绪队列、阻塞队列 { m = int.Parse(textBox4.Text); n = int.Parse(textBox5.Text); a = int.Parse(textBox6.Text); b = int.Parse(textBox7.Text); c = int.Parse(textBox8.Text); a1 = a; b1 = b; c1 = c; r = m - n; time1Inteval = int.Parse(textBox9.Text); timer1.Interval = time1Inteval; for (i = 1; i <= n; i++) { pcb jincheng = new pcb(); jincheng.id = i; jincheng.ra = (random.Next(a) + 1); jincheng.rb = (random.Next(b) + 1); jincheng.rc = (random.Next(c) + 1); jincheng.ntime = (random.Next(1, 5)); jincheng.rtime = 0;

山东大学操作系统实验报告4进程同步实验

山东大学操作系统实验报告4进程同步实验

计算机科学与技术学院实验报告 实验题目:实验四、进程同步实验学号: 日期:20120409 班级:计基地12 姓名: 实验目的: 加深对并发协作进程同步与互斥概念的理解,观察和体验并发进程同步与互斥 操作的效果,分析与研究经典进程同步与互斥问题的实际解决方案。了解 Linux 系统中 IPC 进程同步工具的用法,练习并发协作进程的同步与互斥操作的编程与调试技术。 实验内容: 抽烟者问题。假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽烟。抽烟者卷起并抽掉一颗烟需要有三种材料:烟草、纸和胶水。一个抽烟者有烟草,一个有纸,另一个有胶水。系统中还有两个供应者进程,它们无限地供应所有三种材料,但每次仅轮流提供三种材料中的两种。得到缺失的两种材料的抽烟者在卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。这一过程重复进行。请用以上介绍的 IPC 同步机制编程,实现该问题要求的功能。 硬件环境: 处理器:Intel? Core?i3-2350M CPU @ 2.30GHz ×4 图形:Intel? Sandybridge Mobile x86/MMX/SSE2 内存:4G 操作系统:32位 磁盘:20.1 GB 软件环境: ubuntu13.04 实验步骤: (1)新建定义了producer和consumer共用的IPC函数原型和变量的ipc.h文件。

(2)新建ipc.c文件,编写producer和consumer 共用的IPC的具体相应函数。 (3)新建Producer文件,首先定义producer 的一些行为,利用系统调用,建立共享内存区域,设定其长度并获取共享内存的首地址。然后设定生产者互斥与同步的信号灯,并为他们设置相应的初值。当有生产者进程在运行而其他生产者请求时,相应的信号灯就会阻止他,当共享内存区域已满时,信号等也会提示生产者不能再往共享内存中放入内容。 (4)新建Consumer文件,定义consumer的一些行为,利用系统调用来创建共享内存区域,并设定他的长度并获取共享内存的首地址。然后设定消费者互斥与同步的信号灯,并为他们设置相应的初值。当有消费进程在运行而其他消费者请求时,相应的信号灯就会阻止它,当共享内存区域已空时,信号等也会提示生产者不能再从共享内存中取出相应的内容。 运行的消费者应该与相应的生产者对应起来,只有这样运行结果才会正确。

操作系统实验报告(进程的创建)(DOC)

实验题目进程的创建小组合作否姓名班级学号 一、实验目的 1、了解进程的创建。 2、了解进程间的调用以及实现。 3、分析进程竞争资源的现象,学习解决互斥的方法。 4、加深对进程概念的理解,认识并发执行的本质。 二.实验环境 Windows 系统的计算机一台,安装了Linux虚拟机 三、实验内容与步骤 1、fork()系统调用的使用例子 程序代码: #include #include #include int glob=3; int main(void) { pid_t pid;int loc=3; printf("before fork();glod=%d,loc=%d.\n",glob,loc); if((pid=fork())<0) { printf("fork() error. \n"); exit(0); } else if(pid==0) { glob++; loc--; printf("child process changes glob and loc: \n"); } else

wait(0); printf("parent process doesn't change the glob and loc:\n"); printf("glob=%d,loc=%d\n",glob,loc); exit(0); } 运行结果: 2、理解vofork()调用: 程序代码: #include #include #include int glob=3; int main(void) { pid_t pid; int loc=3; if((pid=vfork())<0) { printf("vfork() error\n"); exit(0); } else if(pid==0) { glob++; loc--; printf("child process changes the glob and loc\n"); exit(0); } else printf ("parent process doesn't change the glob and loc\n"); printf("glob=%d,val=%d\n",glob,loc);

实验二进程同步

实验二进程同步演示 一、实验目的 ?深入掌握进程同步机制——信号量的应用; ?掌握Windows编程中信号量机制的使用方法; ?可进行简单的信号量应用编程。 二、实验工具 Windows系统+ VC++ 6.0 三、实验内容 1、复习教材上信号量机制的定义与应用,复习经典进程同步问题——生产者消费者问题及其同步方案; 2、验证后附的参考代码pc.cpp(生产者消费者问题),掌握Windows系统中信号量的定义与使用方法; 注意: (1)代码中生产者和消费者所做的工作用过程Producer和Consumer描述,并通过创建线程的方法创建3个生产者线程和1个消费者线程,具体创建方法:CreateThread(NULL,0,Producer,NULL,0,&producerID[i]);其中第3个参数就是指定该线程所做的工作为过程Producer; (2)问题中设置了三个信号量g_hMutex(用于互斥访问临界区buffer)、 g_hFullSemaphore、g_hEmptySemaphore(用于控制同步的资源信号量),先声明,再定义,最后使用。互斥信号量和资源信号量的定义方法不同: g_hMutex = CreateMutex(NULL,FALSE,NULL); 互斥信号量最开始没有指定针对那个资源g_hFullSemaphore = CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1,NULL); 其中第2和3个参数为信号量的初始值和最大值 信号量的使用方法:WaitForSingleObject为信号量的P操作,每对一个信号量执行该操作,则信号量值减1,并判断减1后值是否仍大于等于0,如是则该操作成功,否则进程阻塞;ReleaseSemaphore为信号量的V操作,每执行一次将该信号量的值加1,并起到唤醒作用。如: WaitForSingleObject(g_hFullSemaphore,INFINITE); … ReleaseSemaphore(g_hEmptySemaphore,1,NULL);

进程的同步实验报告

操作系统 实验报告 哈尔滨工程大学 计算机科学与技术学院

一、实验概述 1. 实验名称 进程的同步 2. 实验目的 ⑴使用EOS的信号量,编程解决生产者 消费者问题,理解进程同步的意义。 ⑵调试跟踪EOS信号量的工作过程,理解进程同步的原理。 ⑶修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。 3. 实验类型 验证+设计 4. 实验内容 ⑴准备实验 ⑵使用EOS的信号量解决生产者-消费者问题 ⑶调试EOS信号量的工作过程 ①创建信号量 ②等待释放信号量 ③等待信号量(不阻塞) ④释放信号量(不唤醒) ⑤等待信号量(阻塞) ⑥释放信号量(唤醒) ⑷修改EOS的信号量算法 二、实验环境 WindowsXP + EOS集成实验环境 三、实验过程 1. 设计思路和流程图

图4-1.整体试验流程图

图4-2.Main 函数流程图、生产者消费、消费者流程图 2. 算法实现 3. 需要解决的问题及解答 (1). 思考在ps/semaphore.c 文件内的PsWaitForSemaphore 和PsReleaseSemaphore 函数中,为什么要使用原子操作?

答:在执行等待信号量和释放信号量的时候,是不允许cpu响应外部中断的,如果此时cpu响应了外部中断,会产生不可预料的结果,无法正常完成原子操作。 (2). 绘制ps/semaphore.c文件内PsWaitForSemaphore和PsReleaseSemaphore函数的流程图。 (3).P143生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?生产者和消费者是怎样使用同步对象来实现该同步过程的呢? 答:这是因为临界资源的限制。临界资源就像产品仓库,只有“产品仓库”空闲生产者才能生产东西,有权向里面放东西。所以它必须等到消费者,取走产品,“产品空间”(临界资源)空闲时,才继续生产14号产品。 (4). 根据本实验3.3.2节中设置断点和调试的方法,自己设计一个类似的调试方案来验证消费者线程在消费24号产品时会被阻塞,直到生产者线程生产了24号产品后,消费者线程才被唤醒并继续执行的过程。 答:可以按照下面的步骤进行调试 (1) 删除所有的断点。 (2) 按F5启动调试。OS Lab会首先弹出一个调试异常对话框。 (3) 在调试异常对话框中选择“是”,调试会中断。 (4) 在Consumer函数中等待Full信号量的代码行(第173行)WaitForSingleObject(FullSemaphoreHandle, INFINITE); 添加一个断点。 (5) 在“断点”窗口(按Alt+F9打开)中此断点的名称上点击右键。 (6) 在弹出的快捷菜单中选择“条件”。 (7) 在“断点条件”对话框(按F1获得帮助)的表达式编辑框中,输入表达式“i == 24”。 (8) 点击“断点条件”对话框中的“确定”按钮。 (9) 按F5继续调试。只有当消费者线程尝试消费24号产品时才会在该条件断点处中断。 4. 主要数据结构、实现代码及其说明 修改PsWaitForSemaphore函数 if (Semaphore->Count>0){ Semaphore->Count--; flag=STATUS_SUCCESS; }//如果信号量大于零,说明尚有资源,可以为线程分配 else flag=PspWait(&Semaphore->WaitListHead, Milliseconds); KeEnableInterrupts(IntState); // 原子操作完成,恢复中断。 return flag; }//否则,说明资源数量不够,不能再为线程分配资源,因此要使线程等待 修改PsReleaseSemaphore函数 if (Semaphore->Count + ReleaseCount > Semaphore->MaximumCount) {

实验21 进程调度

实验2、1 进程调度 一、 实验目的 多道程序设计中,经常就是若干个进程同时处于就绪状态,必须依照某种策略来决定那个进程优先占有处理机。因而引起进程调度。本实验模拟在单处理机情况下的处理机调度问题,加深对进程调度的理解。 二、 实验要求 1. 设计进程调度算法,进程数不定 2. 包含几种调度算法,并加以实现 3. 输出进程的调度过程——进程的状态、链表等。 三、 参考例 1.题目——优先权法、轮转法 简化假设 1) 进程为计算型的(无I/O) 2) 进程状态:ready 、running 、finish 3) 进程需要的CPU 时间以时间片为单位确定 2.算法描述 1) 优先权法——动态优先权 当前运行进程用完时间片后,其优先权减去一个常数。 2) 轮转法 四、 实验流程图 开始 键盘输入进程数n,与调度方法的选择 优先权法? 轮转法 产生n 个进程,对每个进程产生一个PCB,并用随机数产生进程的优先权及进程所需的CPU 时间 按优先权大小,把n 个进程拉成一个就绪队列 撤销进程就绪队列为空? 结束 N Y Y

注意: 1.产生的各种随机数的取值范围加以限制,如所需的CPU 时间限制在1~20之间。 2.进程数n 不要太大通常取4~8个 3.使用动态数据结构 4.独立编程 5.至少三种调度算法 6.若有可能请在图形方式下,将PCB 的调度用图形成动画显示。 五.实验过程: (1)输入:进程流文件(1、txt),其中存储的就是一系列要执行的进程, 每个作业包括四个数据项: 进程名 进程状态(1就绪 2等待 3运行) 所需时间 优先数(0级最高) 进程0 1 50 2 进程1 2 10 4 进程2 1 15 0 进程3 3 28 5 进程4 2 19 1 进程5 3 8 7 输出: 进程执行流等待时间,平均等待时间 本程序包括:FIFO 算法,优先数调度算法,时间片轮转调度算法 产生n 个进程, 的时间片数,已占用CPU 的时间片数置为0 按进程产生的先后次序拉成就绪队列链 =0? 撤销该进程 就绪队列为空不? =轮转时间片数? N Y Y Y 结束 N

进程间通信实验报告

进程间通信实验报告 班级:10网工三班学生姓名:谢昊天学号:1215134046 实验目的和要求: Linux系统的进程通信机构 (IPC) 允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉Linux支持的消息通讯机制及信息量机制。 实验内容与分析设计: (1)消息的创建,发送和接收。 ①使用系统调用msgget (), msgsnd (), msgrev (), 及msgctl () 编制一长度为1k 的消息的发送和接收程序。 ②观察上面的程序,说明控制消息队列系统调用msgctl () 在此起什么作用? (2)共享存储区的创建、附接和段接。 使用系统调用shmget(),shmat(),sgmdt(),shmctl(),编制一个与上述功能相同的程序。(3)比较上述(1),(2)两种消息通信机制中数据传输的时间。 实验步骤与调试过程: 1.消息的创建,发送和接收: (1)先后通过fork( )两个子进程,SERVER和CLIENT进行通信。 (2)在SERVER端建立一个Key为75的消息队列,等待其他进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出SERVER 。SERVER每接收到一个消息后显示一句“(server)received”。 (3)CLIENT端使用Key为75的消息队列,先后发送类型从10到1的消息,然后退出。最后的一个消息,既是 SERVER端需要的结束信号。CLIENT每发送一条消息后显示一句“(client)sent”。 (4)父进程在 SERVER和 CLIENT均退出后结束。 2.共享存储区的创建,附接和断接: (1)先后通过fork( )两个子进程,SERVER和CLIENT进行通信。 (2)SERVER端建立一个KEY为75的共享区,并将第一个字节置为-1。作为数据空的标志.等待其他进程发来的消息.当该字节的值发生变化时,表示收到了该消息,进行处理.然后再次把它的值设为-1.如果遇到的值为0,则视为结束信号,取消该队列,并退出SERVER.SERVER 每接收到一次数据后显示”(server)received”. (3)CLIENT端建立一个为75的共享区,当共享取得第一个字节为-1时, Server端空闲,可发送请求. CLIENT 随即填入9到0.期间等待Server端再次空闲.进行完这些操作后, CLIENT退出. CLIENT每发送一次数据后显示”(client)sent”. (4)父进程在SERVER和CLIENT均退出后结束。 实验结果: 1.消息的创建,发送和接收: 由 Client 发送两条消息,然后Server接收一条消息。此后Client Server交替发送和接收消息。最后一次接收两条消息。Client 和Server 分别发送和接收了10条消息。message 的传送和控制并不保证完全同步,当一个程序不再激活状态的时候,它完全可能继续睡眠,造成上面现象。在多次send message 后才 receive message.这一点有助于理解消息转送的实现机理。

进程同步实验报告

实验三进程的同步 一、实验目的 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)创建两个子进程:

进程调度算法实验报告

操作系统实验报告(二) 实验题目:进程调度算法 实验环境:C++ 实验目的:编程模拟实现几种常见的进程调度算法,通过对几组进程分别使用不同的调度算法,计算进程的平均周转时间和平均带权周转时间,比较 各种算法的性能优劣。 实验内容:编程实现如下算法: 1.先来先服务算法; 2.短进程优先算法; 3.时间片轮转调度算法。 设计分析: 程序流程图: 1.先来先服务算法 开始 初始化PCB,输入进程信息 各进程按先来先到的顺序进入就绪队列 结束 就绪队列? 运行 运行进程所需CPU时间 取消该进程 2.短进程优先算法

3.时间片轮转调度算法 实验代码: 1.先来先服务算法 #include #define n 20 typedef struct { int id; //进程名

int atime; //进程到达时间 int runtime; //进程运行时间 }fcs; void main() { int amount,i,j,diao,huan; fcs f[n]; cout<<"请输入进程个数:"<>amount; for(i=0;i>f[i].id; cin>>f[i].atime; cin>>f[i].runtime; } for(i=0;if[j+1].atime) {diao=f[j].atime; f[j].atime=f[j+1].atime; f[j+1].atime=diao; huan=f[j].id; f[j].id=f[j+1].id; f[j+1].id=huan; } } } for(i=0;i #define n 5 #define num 5 #define max 65535 typedef struct pro { int PRO_ID; int arrive_time;

实验二进程同步实验

实验二进程同步 一、实验目的: 掌握基本的同步算法,理解经典进程同步问题的本质;学习使用Linux的进程同步机制,掌握相关API的使用方法;能利用信号量机制,采用多种同步算法实现不会发生死锁的哲学家进餐程序。 二、实验平台: 虚拟机:VMWare9以上 操作系统:以上 编辑器:Gedit | Vim 编译器:Gcc 三、实验内容: (1)以哲学家进餐模型为依据,在Linux控制台环境下创建5个进程,用semget函数创建一个信号量集(5个信号量,初值为1),模拟哲学家的思考和进餐行为:每一位哲学家饥饿时,先拿起左手筷子,再拿起右手筷子;筷子是临界资源,为每一支筷子定义1个互斥信号量;想拿到筷子需要先对信号量做P操作,使用完释放筷子对信号量做V操作。 伪代码描述: semaphore chopstick[5]={1,1,1,1,1}; ?第i位哲学家的活动可描述为: do{ printf("%d is thinking\n",i); printf("%d is hungry\n",i); wait(chopstick[i]); 当哲学家的左、右两只筷子均可用时,才允许他拿起筷子进餐;b.至多只允许有4位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐;c.规定奇数号哲学家先拿起他左手的筷子,然后再拿起他右手的筷子,而偶数号哲学家则先拿起他右手的筷子,然后再拿起他左手的筷子。方法a在示例程序中给出,请用方法b和c写出不会发生死锁的哲学家进餐程序。 (3)设计程序,实现生产者/消费者进程(线程)的同步与互斥。在该程序中创建4个进程(或线程)模拟生产者和消费者,实现进程(线程)的同步与互斥。

实验一 单处理器系统进程调度(正确)

实验一单处理器系统进程调度 一、实验目的 1.加深对进程概念的理解,明确进程和程序的区别。 2.深入了解系统如何组织进程、创建进程。 3.进一步认识如何实现处理器调度。 二、实验预备知识 1.进程的概念。 2.进程的组织方式。 3.进程的创建。 4.进程的调度。 三、实验内容 编写程序完成单处理机系统中的进程调度,要求采取用时间片轮转调度算法。试验具体包括:首先确定进程控制块的内容,进程控制块的组成方式;然后完成进程创建、调度原语;最后编写主函数对所做工作进行测试。 四、提示 这个实验主要要考虑三个问题:如何组织进程、如何创建进程和如何实现处理器调度。 考虑如何组织进程,首先就要设定进程控制块的内容。进程控制块PCB,记录各个进程执时的情况。不同的操作系统,进程控制块记录的信息内容不_样。操作系统功能越强,软件也越庞大,进程控制块记录的内容也就越多。这里的实验只使用了必不可少~信息。一般操作系统中,无论进程控制块中信息量多少,信息都可以大致分为以下四类: (1)标识信息 每个进程都要有一个惟一的标识符,用来标识进程的存在和区别于其他进程。这个标识符是必不可少的,可以用符号或编号实现,它必须是操作系统分配的。在后面给出的参考程序中,采用编号方式,也就是为每个进程依次分配一个不相同的正整数。 (2)说明信息 用于记录进程的基本情况,例如进程的状态、等待原因、进程程序存放位置、进程数据存放位置等等。实验中,因为进程没有数据和程序,仅使用进程控制块模拟进程,。所以这部分内容仅包括进程状态。 {int head; int tail; }ready;//定义指向就绪队列的头指针head和尾指针tail int pfree;//定义指向空闲进程控制块队列的指针 进程创建是一个原语,因此在实验中应该用一个函数实现,进程创建的过程应该包括: (1)申请进程控制块:进程控制块的数量是有限的,如果没有空闲进程控制块,则进程 不能创建,如果申请成功才可以执行第二步; (2)申请资源:除了进程控制块外,还需要有必要的资源才能创建进程,如果申请资 源不成功,则不能创建进程,并且归还已申请的进程控制块:如果申请成功,则执行第三步,实验无法申请资源,所以模拟进程忽略了申请资源这一步 (3)填写进程控制块:将该进程信息写入进程控制块内,实验中只有进程标识符、进 程状态可以填写,每个进程现场信息中的寄存器内容由于没有具体数据而使用进程(模拟进程创建时,需输入进程标识符字,进程标识符本应系统建立,并且是惟一一的,输入时注

实验三进程调度蔡凤武

实验三进程调度蔡凤武 进程调度实验目的 1、理解有关进程控制块、进程队列的概念。 2、掌握进程优先权调度算法和时间片轮转调度算法的处理逻辑。 实验内容与基本要求 1、设计进程控制块PCB的结构,分别适用于优先权调度算法和时间片轮转调度算法。 2、建立进程就绪队列。 3、编制两种进程调度算法:优先权调度算法和时间片轮转调度算法。 实验报告内容一.优先权调度算法和时间片轮转调度算法原理。对于优先权调度算法,其关键是在于是采用静态优先权还是动态优先权,以及如何确定进程的优先权。静态优先权是在创建进程是确定的,并且规定它在进程的整个运行期间保持不变。动态优先权要配合抢占调度方式使用,它是指在创建进程时所赋予的优先权,可以随着进程的推进而发生改变,以便获得更好的调度性能。在就绪队列中等待调度的进程,可以随着等待时间的增加,其优先权也以某个速率增加。因此,对于优先权初值很低的进程,在等待足够时间后,其优先权也可能升为最高,从而获得调度,占用处理器并执行。对已时间片轮转调度算法,系统将所

有的就绪进程按进路就绪队列的先后次序排列。每次调度时把CPU 分配给队首进程,让其执行一个时间片,当时间片用完,由计时器发出时钟中断,调度程序则暂停改程序的执行,使其退出处理器,并将它送人就绪队的末尾,等待下一轮调度执行。然后,把cpu分配给就绪队列中新的队首进程,同时让它执行一个时间片。二.程序流程图。结束就绪队列为空吗三.程序及注释。 #include #include #include #include #include #include #define P_NUM5#define P_TIME50 enum st { ready, execute, block, finish};//状态定义进程//struct pcb{ char name[4];//进程名字// int priority;//进程优先权// int cputime;//CPU运行时间// int needtime;//进程运行需要的时间// int count;//进程执行次数// int round;//时间片轮转轮次// st process;//进程状态// pcb *next;};//定义进程//pcb *get_process(){ pcb *q; pcb *t; pcb *p; int i=0; cout<<"input name and time"<>q->name; cin>>q->needtime; q->cputime=0; q->priority=P_TIME-q- >needtime; q->process=ready; q->next=NULL; if(i==0) { p=q; t=q; } else { t->next=q; t=q;} i++; } return p;//输入模拟测试的进程名和执行所需的时间,初始设置可模拟5个进程的调度//}void display (pcb *p){ cout<<"name"<<"

相关文档
最新文档