当前位置:文档之家› 操作系统 实验 进程的同步

操作系统 实验 进程的同步

操作系统 实验 进程的同步
操作系统 实验 进程的同步

操作系统

实验报告

哈尔滨工程大学

计算机科学与技术学院

第四讲进程的同步

一、实验概述

1. 实验名称

进程的同步

2. 实验目的

使用EOS的信号量,编程解决生产者—消费者问题,理解进程同步的意义。

调试跟踪EOS信号量的工作过程,理解进程同步的原理。

修改EOS的信号量算法,使之支持等待超时唤醒功能(有限等待),加深理解进程同步的原理。

3. 实验类型

验证+设计

4. 实验内容

(1)准备实验

(2)使用EOS的信号量解决生产者-消费者问题

(3)调试EOS信号量的工作过程

(4)修改EOS的信号量算法

二、实验环境

EOS操作系统和OS Lab集成实验环境,主要运用了C语言。

三、实验过程

3. 需要解决的问题及解答

(1)P143,生产者在生产了13号产品后本来要继续生产14号产品,可此时生产者为什么必须等待消费者消费了4号产品后,才能生产14号产品呢?生产者和消费者是怎样使用同步对象来实现该同步过程的呢?

这是因为临界资源的限制。临界资源就像产品仓库,只有“产品仓库”空闲生产者才能生产东西,有权向里面放东西。因此它必须要等到消费者,取走产品,临界资源空闲时,才能继续生产14号产品。

(2)P147-四思考与练习-2. 绘制ps/semaphore.c文件内PsWaitForSemaphore和PsReleaseSemaphore函数的流程图。

5. 源程序并附上注释

#include "psp.h"

VOID

PsInitializeSemaphore(

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

STATUS

PsWaitForSemaphore(IN PSEMAPHORE Semaphore,IN INT Milliseconds,IN STATUS i )

/*++

功能描述:信号量的Wait 操作(P 操作)。

参数:Semaphore -- Wait 操作的信号量对象。

Milliseconds -- 等待超时上限,单位毫秒。返回值:

STATUS_SUCCESS。

--*/

{BOOL IntState;

ASSERT(KeGetIntNesting() == 0); // 中断环境下不能调用此函数。

IntState = KeEnableInterrupts(FALSE); // 开始原子操作,禁止中断。

// 目前仅实现了标准记录型信号量,不支持超时唤醒功能,所以PspWait 函数的第二个参数的值只能是INFINITE。

if(Semaphore->Count > 0)

{ Semaphore->Count--;

i=STATUS_SUCCESS;}

else {i=PspWait(&Semaphore->WaitListHead,Milliseconds );}

KeEnableInterrupts(IntState); // 原子操作完成,恢复中断。

return i;

}

STATUS

PsReleaseSemaphore(IN PSEMAPHORE Semaphore,IN LONG ReleaseCount,OUT PLONG PreviousCount)

/*++

功能描述:信号量的Signal 操作(V 操作)。

参数:Semaphore -- Wait 操作的信号量对象。

-- 信号量计数增加的数量。当前只能为1。当你修改信号量使之支持超时唤醒功能后,此参数的值能够大于等于1。

PreviousCount -- 返回信号量计数在增加之前的值。

返回值:如果成功释放信号量,返回STATUS_SUCCESS。

--*/

{STATUS Status;

BOOL IntState;

IntState = KeEnableInterrupts(FALSE); // 开始原子操作,禁止中断。

if (Semaphore->Count + ReleaseCount > Semaphore->MaximumCount) {

Status = STATUS_SEMAPHORE_LIMIT_EXCEEDED;

} else {

if (NULL != PreviousCount) {

*PreviousCount = Semaphore->Count;}

INT j=Semaphore->Count;

while((!ListIsEmpty(&Semaphore->WaitListHead))&&(ReleaseCount)){

PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS);

PspThreadSchedule();

ReleaseCount--;

}

Semaphore->Count=j+ReleaseCount;

Status = STATUS_SUCCESS;

}

KeEnableInterrupts(IntState); // 原子操作完成,恢复中断。

return Status;

}

POBJECT_TYPE PspSemaphoreType = NULL;// 用于初始化semaphore 结构体的参数结构体。typedef struct _SEM_CREATE_PARAM{

LONG InitialCount;

LONG MaximumCount;

}SEM_CREATE_PARAM, *PSEM_CREATE_PARAM;

// semaphore 对象的构造函数,在创建新semaphore 对象时被调用。

VOID

PspOnCreateSemaphoreObject(

IN PVOID SemaphoreObject,

IN ULONG_PTR CreateParam

)

{PsInitializeSemaphore( (PSEMAPHORE)SemaphoreObject,

((PSEM_CREATE_PARAM)CreateParam)->InitialCount,

((PSEM_CREATE_PARAM)CreateParam)->MaximumCount ); }

//

// semaphore 对象类型的初始化函数。

//

VOID

PspCreateSemaphoreObjectType(VOID)

{STATUS Status;

OBJECT_TYPE_INITIALIZER Initializer;

Initializer.Create = PspOnCreateSemaphoreObject;

Initializer.Delete = NULL;

Initializer.Wait = (OB_WAIT_METHOD)PsWaitForSemaphore;

Initializer.Read = NULL;

Initializer.Write = NULL;

Status = ObCreateObjectType("SEMAPHORE", &Initializer, &PspSemaphoreType);

if (!EOS_SUCCESS(Status)) {

KeBugCheck("Failed to create semaphore object type!");

}}

//

// semaphore 对象的构造函数。

//

STATUS

PsCreateSemaphoreObject(

IN LONG InitialCount,

IN LONG MaximumCount,

IN PSTR Name,

OUT PHANDLE SemaphoreHandle

)

{ STATUS Status;

PVOID SemaphoreObject;

SEM_CREATE_PARAM CreateParam;

if(InitialCount < 0 || MaximumCount <= 0 || InitialCount > MaximumCount){

return STATUS_INV ALID_PARAMETER;

}

// 创建信号量对象。

CreateParam.InitialCount = InitialCount;

CreateParam.MaximumCount = MaximumCount;

Status= ObCreateObject( PspSemaphoreType, Name, sizeof(SEMAPHORE), (ULONG_PTR)&CreateParam &SemaphoreObject);

if (!EOS_SUCCESS(Status)) { return Status; }

Status = ObCreateHandle(SemaphoreObject, SemaphoreHandle);

if (!EOS_SUCCESS(Status)) {ObDerefObject(SemaphoreObject);}

return Status;

}

//

// semaphore 对象的signal 操作函数。

//

STATUS

PsReleaseSemaphoreObject(IN HANDLE Handle,IN LONG ReleaseCount,IN PLONG PreviousCount)

{STATUS Status;

PSEMAPHORE Semaphore;

if (ReleaseCount < 1) {return STATUS_INV ALID_PARAMETER;}

// 由semaphore 句柄得到semaphore 对象的指针。

Status = ObRefObjectByHandle(Handle, PspSemaphoreType, (PVOID*)&Semaphore);

if (EOS_SUCCESS(Status)) {

Status = PsReleaseSemaphore(Semaphore, ReleaseCount, PreviousCount);

ObDerefObject(Semaphore);

}

return Status;

}

#include "EOSApp.h"

// 缓冲池。

#define BUFFER_SIZE 10

int Buffer[BUFFER_SIZE];

// 产品数量。

#define PRODUCT_COUNT 30

// 用于生产者和消费者同步的对象句柄。

HANDLE MutexHandle;

HANDLE EmptySemaphoreHandle;

HANDLE FullSemaphoreHandle;

// 生产者和消费者的线程函数

ULONG Producer(PVOID Param);

ULONG Consumer(PVOID Param);

// main 函数参数的意义:

// argc - argv 数组的长度,大小至少为1,argc - 1 为命令行参数的数量。

// argv - 字符串指针数组,数组长度为命令行参数个数+ 1。其中argv[0] 固定指向当前进程所执行的可执行文件的路径//符串,argv[1] 及其后面的指针指向各个命令行参数。

int main(int argc, char* argv[])

{HANDLE ProducerHandle;

HANDLE ConsumerHandle;

#ifdef _DEBUG

__asm("int $3\n nop");

#endif

// 创建用于互斥访问缓冲池的Mutex 对象。

MutexHandle = CreateMutex(FALSE, NULL);

if (NULL == MutexHandle) {return 1;}

// 创建Empty 信号量,表示缓冲池中空缓冲区数量。初始计数和最大计数都为BUFFER_SIZE。EmptySemaphoreHandle = CreateSemaphore(BUFFER_SIZE, BUFFER_SIZE, NULL);

if (NULL == EmptySemaphoreHandle) {return 2;}

// 创建Full 信号量,表示缓冲池中满缓冲区数量。初始计数为0,最大计数为BUFFER_SIZE。FullSemaphoreHandle = CreateSemaphore(0, BUFFER_SIZE, NULL);

if (NULL == FullSemaphoreHandle) {return 3;}

// 创建生产者线程。

ProducerHandle = CreateThread( 0, // 默认堆栈大小

Producer, // 线程函数入口地址

NULL, // 线程函数参数

0, // 创建标志

NULL ); // 线程ID

if (NULL == ProducerHandle) {

return 4;}

// 创建消费者线程。

ConsumerHandle = CreateThread( 0,Consumer,NULL,0,NULL );

if (NULL == ConsumerHandle) {return 5;}

// 等待生产者线程和消费者线程结束。

WaitForSingleObject(ProducerHandle, INFINITE);

WaitForSingleObject(ConsumerHandle, INFINITE);

// 关闭句柄

CloseHandle(MutexHandle);

CloseHandle(EmptySemaphoreHandle);

CloseHandle(FullSemaphoreHandle);

CloseHandle(ProducerHandle);

CloseHandle(ConsumerHandle);

return 0;

}

// 生产者线程函数。

ULONG Producer(PVOID Param)

{ int i;

int InIndex = 0;

for (i = 0; i < PRODUCT_COUNT; i++) {

while(WAIT_TIMEOUT == WaitForSingleObject(EmptySemaphoreHandle, 300)){ printf("Producer wait for empty semaphore timeout\n");

}

WaitForSingleObject(MutexHandle, INFINITE);

printf("Produce a %d\n", i);

Buffer[InIndex] = i;

InIndex = (InIndex + 1) % BUFFER_SIZE;

ReleaseMutex(MutexHandle);

ReleaseSemaphore(FullSemaphoreHandle, 1, NULL);

// 休息一会。每500 毫秒生产一个数。

Sleep(500);}

return 0;}

// 消费者线程函数。

ULONG Consumer(PVOID Param)

{int i;

int OutIndex = 0;

for (i = 0; i < PRODUCT_COUNT; i++) {

while(WAIT_TIMEOUT == WaitForSingleObject(FullSemaphoreHandle, 300)){ printf("Consumer wait for full semaphore timeout\n");

}

WaitForSingleObject(MutexHandle, INFINITE);

printf("\t\t\tConsume a %d\n", Buffer[OutIndex]);

OutIndex = (OutIndex + 1) % BUFFER_SIZE;

ReleaseMutex(MutexHandle);

ReleaseSemaphore(EmptySemaphoreHandle, 1, NULL);

// 休息一会儿。让前10 个数的消费速度比较慢,后面的较快。

if (i < 10) {Sleep(2000);} else {Sleep(100);} }return 0;}

6. 程序运行时的初值和运行结果

3.1 准备实验

1. 启动OS Lab。

2. 新建一个EOS Kernel项目。

3. 生成EOS Kernel项目,从而在该项目文件夹中生成SDK文件夹。

4. 新建一个EOS应用程序项目。

5. 使用在第3步生成的SDK文件夹覆盖EOS应用程序项目文件夹中的SDK文件夹。

3.2 使用EOS的信号量解决生产者-消费者问题

1.使用pc.c文件中的源代码,替换之前创建的EOS应用程序项目中EOSApp.c文件内的源代码。

2. 按F7生成修改后的EOS应用程序项目。

3. 按F5启动调试。OS Lab会首先弹出一个调试异常对话框。

4. 在调试异常对话框中选择“否”,继续执行。

5. 立即激活虚拟机窗口查看生产者-消费者同步执行的过程。

6. 待应用程序执行完毕后,结束此次调试。

3.3 调试EOS信号量的工作过程

3.3.1 创建信号量

1. 按F5启动调试EOS应用项目。OS Lab会首先弹出一个调试异常对话框。

2. 在调试异常对话框中选择“是”,调试会中断。

3. 在main函数中创建Empty信号量的代码行,第77行添加一个断点。

4. 按F5继续调试,到此断点处中断。

5. 按F11调试进入CreateSemaphore函数。可以看到此API函数只是调用了EOS内核中的PsCreateSemaphoreObject函数来创建信号量对象。

6. 按F11调试进入semaphore.c文件中的PsCreateSemaphoreObject函数。在此函数中,会在EOS内核管理的内存中创建一个信号量对象(分配一块内存),而初始化信号量对象中各个成员的操作是在PsInitializeSemaphore函数中完成的。

7. 在semaphore.c文件的顶部查找到PsInitializeSemaphore函数的定义(第19行),在此函数的第一行(第39行)代码处添加一个断点。

8. 按F5继续调试,到断点处中断。观察PsInitializeSemaphore函数中用来初始化信号量结构体成员的值,应该和传入CreateSemaphore函数的参数值是一致的。

9. 按F10单步调试PsInitializeSemaphore函数执行的过程,查看信号量结构体被初始化的

过程。打开“调用堆栈”窗口,查看函数的调用层次。

3.3.2 等待、释放信号量

3.3.2.1 等待信号量(不阻塞)

1.删除所有的断点(防止有些断点影响后面的调试)。

2.在eosapp.c文件的Producer函数中,等待Empty信号量的代码行(第144行)添加一个断点。

3.按F5继续调试,到断点处中断。

4.WaitForSingleObject 函数最终会调用内核中的PsWaitForSemaphore函数完成等待操作。所以,在semaphore.c文件中PsWaitForSemaphore函数的第一行(第68行)添加一个断点。

5. 按F5继续调试,到断点处中断。

6. 按F10单步调试,直到完成PsWaitForSemaphore函数中的所有操作。可以看到此次执行并没有进行等待,只是将Empty信号量的计数减少了1(由10变为了9)就返回了。

3.3.2.2 释放信号量(不唤醒)

1. 删除所有的断点(防止有些断点影响后面的调试)。

2. 在eosapp.c文件的Producer函数中,释放Full信号量的代码行(第152行)添加一个断点。

3. 按F5继续调试,到断点处中断。

4. 按F11调试进入ReleaseSemaphore函数。

5. 继续按F11调试进入PsReleaseSemaphoreObject函数。

6. 先使用F10单步调试,当黄色箭头指向第269行时使用F11单步调试,进入PsReleaseSemaphore函数。

7. 按F10单步调试,直到完成PsReleaseSemaphore函数中的所有操作。可以看到此次执行没有唤醒其它线程(因为此时没有线程在Full信号量上被阻塞),只是将Full信号量的计数增加了1(由0变为了1)。

生产者线程通过等待Empty信号量使空缓冲区数量减少了1,通过释放Full信号量使满缓冲区数量增加了1,这样就表示生产者线程生产了一个产品并占用了一个缓冲区。

3.3.2.3 等待信号量(阻塞)

1. 结束之前的调试。

2. 删除所有的断点。

3. 按F5重新启动调试。OS Lab会首先弹出一个调试异常对话框。

4. 在调试异常对话框中选择“是”,调试会中断。

5. 在semaphore.c文件中的PsWaitForSemaphore函数的

代码行(第78行)添加一个断点。

6. 按F5继续调试,并立即激活虚拟机窗口查看输出。开始时生产者、消费者都不会被信号量阻塞,同步执行一段时间后才在断点处中断。

7. 中断后,查看“调用堆栈”窗口,有Producer函数对应的堆栈帧,说明此次调用是从生产者线程函数进入的。

8. 在“调用堆栈”窗口中双击Producer函数所在的堆栈帧,绿色箭头指向等待Empty信号量的代码行,查看Producer函数中变量i的值为14,表示生产者线程正在尝试生产14号产品。

9. 在“调用堆栈”窗口中双击PsWaitForSemaphore函数的堆栈帧,查看Empty信号量计数(Semaphore->Count)的值为-1,所以会调用PspWait函数将生产者线程放入Empty信号量的等待队列中进行等待(让出CPU)。

10. 激活虚拟机窗口查看输出的结果。生产了从0到13的14个产品,但是只消费了从0到3的4个产品,所以缓冲池中的10个缓冲区就都被占用了,这与之前调试的结果是一致的。

3.3.2.4 释放信号量(唤醒)

1. 删除所有断点。

2.在eosapp.c文件的Consumer函数中,释放Empty信号量的代码行(第180行)添加一个断点。

3. 按F5继续调试,到断点处中断。

4. 查看Consumer函数中变量i的值为4,说明已经消费了4号产品。

5. 按照3.3.2.2中的方法使用F10和F11调试进入PsReleaseSemaphore函数。

6. 查看PsReleaseSemaphore函数中Empty信号量计数(Semaphore->Count)的值为-1,和生产者线程被阻塞时的值是一致的。

7. 按F10单步调试PsReleaseSemaphore函数,直到在代码行(第132行)PspWakeThread(&Semaphore->WaitListHead, STATUS_SUCCESS); 处中断。此时Empty信号量计数的值已经由-1增加为了0,需要调用PspWakeThread函数唤醒阻塞在Empty信号量等待队列中的生产者线程(放入就绪队列中),然后调用PspSchedule函数执行调度,这样生产者线程就得以继续执行。

按照下面的步骤验证生产者线程被唤醒后,是从之前被阻塞时的状态继续执行的:

1.在semaphore.c文件中PsWaitForSemaphore函数的最后一行代码处添加一个断点。

2. 按F5继续调试,在断点处中断。

3. 查看PsWaitForSemaphore函数中Empty信号量计数(Semaphore->Count)的值为0,和生产者线程被唤醒时的值是一致的。

4. 在“调用堆栈”窗口中可以看到是由Producer函数进入的。激活Producer函数的堆栈帧,查看Producer函数中变量i的值为14,表明之前被阻塞的、正在尝试生产14号产品的生产者线程已经从PspWait函数返回并继续执行了。

5. 结束此次调试。

3.4 修改EOS的信号量算法

3.4.3 测试方法

按照要求,修改完毕后,可以按照下面的方法进行测试:

1. 使用修改完毕的EOS Kernel项目生成完全版本的SDK文件夹,并覆盖之前的生产者-消费者应用程序项目的SDK文件夹。

2. 按F5调试执行原有的生产者-消费者应用程序项目。如果有错误,可以调试内核代码来查找错误,然后在内核项目中修改,并重复步骤1。

3. 将Producer函数中等待Empty信号量的代码行

WaitForSingleObject(EmptySemaphoreHandle, INFINITE);

替换为 while(WAIT_TIMEOUT == WaitForSingleObject(EmptySemaphoreHandle,

300)){ printf("Producer wait for empty semaphore timeout\n"); }

4. 将Consumer函数中等待Full信号量的代码行

WaitForSingleObject(FullSemaphoreHandle, INFINITE); 替换为 while(WAIT_TIMEOUT == WaitForSingleObject(FullSemaphoreHandle, 300)){ printf("Consumer wait for full semaphore timeout\n"); }

5. 启动调试新的生产者-消费者项目,查看在虚拟机中输出的结果,验证信号量超时等待功能是否能够正常执行。如果有错误,可以调试内核代码来查找错误,然后在内核项目中修改,并重复步骤1。

6. 如果超时等待功能已经能够正常执行,可以考虑将消费者线程修改为一次消费两个产品,来测试ReleaseCount参数是否能够正常使用。使用实验文件夹中NewConsumer.c文件中的Consumer函数替换原有的Consumer函数。

四、实验体会

操作系统OS报告读者与写者问题(进程同步问题)

目录 一、课程设计目的及要求 (1) 二、相关知识 (1) 三、题目分析 (2) 四、概要设计 (4) 五、代码及流程 (5) 六、运行结果 (11) 七、设计心得 (12) 八、参考文献 (12)

一、课程设计目的及要求 读者与写者问题(进程同步问题) 用n 个线程来表示n个读者或写者。每个线程按相应测试数据文件的要求,进行读写操作。请用信号量机制分别实现读者优先和写者优先的读者-写者问题。 读者-写者问题的读写操作限制: 1)写-写互斥; 2)读-写互斥; 3)读-读允许; 写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。 二、相关知识 Windows API: 在本实验中涉及的API 有: 1线程控制: CreateThread 完成线程创建,在调用进程的地址空间上创建一个线程,以执行指定的函数;它的返回值为所创建线程的句柄。 HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD DWORD dwStackSize, // initial stack size LPTHREAD_START_ROUTINE lpStartAddress, // thread function LPVOID lpParameter, // thread argument DWORD dwCreationFlags, // creation option LPDWORD lpThreadId // thread identifier ); 2 ExitThread 用于结束当前线程。 VOID ExitThread( DWORD dwExitCode // exit code for this thread ); 3Sleep 可在指定的时间内挂起当前线程。 VOID Sleep( DWORD dwMilliseconds // sleep time ); 4信号量控制: WaitForSingleObject可在指定的时间内等待指定对象为可用状态; DWORD WaitForSingleObject( HANDLE hHandle, // handle to object DWORD dwMilliseconds // time-out interval );

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

实验一进程管理 一、目的 进程调度是处理机管理的核心内容。本实验要求编写和调试一个简单的进程调度程序。通过本实验加深理解有关进程控制块、进程队列的概念,并体会和了解进程调度算法的具体实施办法。 二、实验内容及要求 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;

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

实验三:进程同步实验 一、实验任务: (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.1 实验目的 加深对于进程并发执行概念的理解。实践并发进程的创建和控制方法。观察和体验进程的动态特性。进一步理解进程生命期期间创建、变换、撤销状态变换的过程。掌握进程控制的方法,了解父子进程间的控制和协作关系。练习Linux 系统中进程创建与控制有关的系统调用的编程和调试技术。 1.2 实验说明 1)与进程创建、执行有关的系统调用说明进程可以通过系统调用fork()创建子进程并和其子进程并发执行.子进程初始的执行映像是父进程的一个复本.子进程可以通过exec()系统调用族装入一个新的执行程序。父进程可以使用wait()或waitpid()系统调用等待子进程的结束并负责收集和清理子进程的退出状态。 fork()系统调用语法: #include pid_t fork(void); fork 成功创建子进程后将返回子进程的进程号,不成功会返回-1. exec 系统调用有一组6 个函数,其中示例实验中引用了execve 系统调用语法: #include int execve(const char *path, const char *argv[], const char * envp[]); path 要装入 的新的执行文件的绝对路径名字符串. argv[] 要传递给新执行程序的完整的命令参数列表(可以为空). envp[] 要传递给新执行程序的完整的环境变量参数列表(可以为空).

Exec 执行成功后将用一个新的程序代替原进程,但进程号不变,它绝不会再返回到调用进程了。如果exec 调用失败,它会返回-1。 wait() 系统调用语法: #include #include pid_t wait(int *status); pid_t waitpid(pid_t pid,int *status,int option); status 用 于保留子进程的退出状态 pid 可以为以下可能值: -1 等待所有PGID 等于PID 的绝对值的子进程 1 等待所有子进程 0 等待所有PGID 等于调用进程的子进程 >0 等待PID 等于pid 的子进程option 规 定了调用waitpid 进程的行为: WNOHANG 没有子进程时立即返回 WUNTRACED 没有报告状态的进程时返回 wait 和waitpid 执行成功将返回终止的子进程的进程号,不成功返回-1。 getpid()系统调用语法: #include #include pid_t getpid(void); pid_t getppid(void); getpid 返回当前进程的进程号,getppid 返回当前进程父进程的进程号 2)与进程控制有关的系统调用说明可以通过信号向一个进程发送消息以控制进程的 行为。信号是由中断或异常事件引发的,如:键盘中断、定时器中断、非法内存引

第二章-操作系统进程(练习题答案)

第二章进程管理 1.操作系统主要是对计算机系统全部 (1) 进行管理,以方便用户、提高计算机使 用效率的一种系统软件。它的主要功能有:处理机管理、存储管理、文件管理、 (2) 管 理和设备管理等。Windows和Unix是最常用的两类操作系统。前者是一个具有图形界面的 窗口式的 (3) 系统软件,后者是一个基本上采用 (4) 语言编制而成的 的系统软件。在 (5) 操作系统控制下,计算机能及时处理由过程控制反馈的信息 并作出响应。 供选答案: (1): A. 应用软件 B. 系统软硬件 C. 资源 D. 设备 (2): A. 数据 B. 作业 C. 中断 D. I/O (3): A. 分时 B. 多任务 C. 多用户 D. 实时 (4): A. PASCAL B. 宏 C. 汇编 D. C (5): A. 网络 B. 分时 C. 批处理 D. 实时 答案:CBBDD 2.操作系统是对计算机资源进行的 (1) 系统软件,是 (2) 的接口。 在处理机管理中,进程是一个重要的概念,它由程序块、 (3) 和数据块三部 分组成,它有3种基本状态,不可能发生的状态转换是 (4) 。 虚拟存储器的作用是允许程序直接访问比内存更大的地址空间,它通常使用 (5) 作为它的一个主要组成部分。 供选答案: (1): A. 输入和输出 B. 键盘操作 C. 管理和控制 D. 汇编和执行 (2): A. 软件和硬件 B. 主机和外设 C. 高级语言和机器语言 D. 用户和计算机 (3): A. 进程控制块 B. 作业控制块 C. 文件控制块 D. 设备控制块 (4): A. 运行态转换为就绪态 B. 就绪态转换为运行态 C. 运行态转换为等待态 D. 等待态转换为运行态 (5): A. 软盘 B. 硬盘 C. CDROM D. 寄存器 答案:CDADB 3.在计算机系统中,允许多个程序同时进入内存并运行,这种方法称为 D。 A. Spodling技术 B. 虚拟存储技术 C. 缓冲技术 D. 多道程序设计技术 4.分时系统追求的目标是 C。 A. 高吞吐率 B. 充分利用内存 C. 快速响应 D. 减少系统开销 5.引入多道程序的目的是 D。

操作系统的进程调度 实验报告

《计算机操作系统2》实验报告 实验一题目:操作系统的进程调度 姓名:学号:12125807 实验日期:2014.12 实验要求: 1.设计一个有n个进程工行的进程调度程序。每个进程由一个进程控制块(PCB)表示。 进程控制块通常应包含下述信息:进程名、进程优先数、进程需要运行的时间、占用CPU的时间以及进程的状态等,且可按调度算法的不同而增删。 2.调度程序应包含2~3种不同的调度算法,运行时可任意选一种,以利于各种算法的分 析比较。 3.系统应能显示或打印各进程状态和参数的变化情况,便于观察诸进程的调度过程 实验目的: 1.进程是操作系统最重要的概念之一,进程调度又是操作系统核心的主要内容。本实习要 求学生独立地用高级语言编写和调试一个简单的进程调度程序。调度算法可任意选择或自行设计。例如,简单轮转法和优先数法等。本实习可加深对于进程调度和各种调度算法的理解。 实验内容: 1.编制和调试示例给出的进程调度程序,并使其投入运行。 2.自行设计或改写一个进程调度程序,在相应机器上调试和运行该程序,其功能应该不亚 于示例。 3.直观地评测各种调度算法的性能。 示例: 1.题目 本程序可选用优先数法或简单轮转法对五个进程进行调度。每个进程处于运行R(run)、就绪W(wait)和完成F(finish)三种状态之一,并假设起始状态都是就绪状态W。为了便于处理,程序进程的运行时间以时间片为单位计算。各进程的优先数或轮转时间片数、以及进程需要运行的时间片数,均由伪随机数发生器产生。 进程控制块结构如下:

PCB 进程标识数 链指针 优先数/轮转时间片数 占用CPU时间片数 进程所需时间片数 进程状态 进程控制块链结构如下: 其中:RUN—当前运行进程指针; HEAD—进程就绪链链首指针; TAID—进程就绪链链尾指针。 2.算法与框图 (1) 优先数法。 进程就绪链按优先数大小从高到低排列,链首进程首先投入运行。每过一个时间片,运行进程所需运行的时间片数减1,说明它已运行了一个时间片,优先数也减3,理由是该进程如果在一个时间片中完成不了,优先级应该降低一级。接着比较现行进程和就绪链链首进程的优先数,如果仍是现行进程高或者相同,就让现行进程继续进行,否则,调度就绪链链首进程投入运行。原运行进程再按其优先数大小插入就绪链,且改变它们对应的进程状态,直至所有进程都运行完各自的时间片数。 (2) 简单轮转法。 进程就绪链按各进程进入的先后次序排列,进程每次占用处理机的轮转时间按其重要程度登入进程控制块中的轮转时间片数记录项(相当于优先数法的优先数记录项位置)。每过一个时间片,运行进程占用处理机的时间片数加1,然后比较占用处理机的时间片数是否与该进程的轮转时间片数相等,若相等说明已到达轮转时间,应将现运行进程排到就绪链末尾,调度链首进程占用处理机,且改变它们的进程状态,直至所有进程完成各自的时间片。(3) 程序框图如下图所示。

操作系统实验实验1

广州大学学生实验报告 1、实验目的 1.1、掌握进程的概念,明确进程的含义 1.2、认识并了解并发执行的实质 2.1、掌握进程另外的创建方法 2.2、熟悉进程的睡眠、同步、撤消等进程控制方法 3.1、进一步认识并发执行的实质 3.2、分析进程竞争资源的现象,学习解决进程互斥的方法 4.1、了解守护进程 5.1、了解什么是信号 5.2、INUX系统中进程之间软中断通信的基本原理 6.1、了解什么是管道 6.2、熟悉UNIX/LINUX支持的管道通信方式 7.1、了解什么是消息 7.2、熟悉消息传送的机理 8.1、了解和熟悉共享存储机制 二、实验内容 1.1、编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统 中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。试观察记录屏幕上的显示结果,并分析原因。 1.2、修改上述程序,每一个进程循环显示一句话。子进程显示'daughter …'及 'son ……',父进程显示'parent ……',观察结果,分析原因。 2.1、用fork( )创建一个进程,再调用exec( )用新的程序替换该子进程的内容 2.2、利用wait( )来控制进程执行顺序 3.1、修改实验(一)中的程序2,用lockf( )来给每一个进程加锁,以实现进程之间的互斥 3.2、观察并分析出现的现象 4.1、写一个使用守护进程(daemon)的程序,来实现: 创建一个日志文件/var/log/Mydaemon.log ; 每分钟都向其中写入一个时间戳(使用time_t的格式) ; 5.1、用fork( )创建两个子进程,再用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止: Child process1 is killed by parent! Child process2 is killed by parent! 父进程等待两个子进程终止后,输出如下的信息后终止: Parent process is killed! 5.2、用软中断通信实现进程同步的机理

山东大学操作系统实验报告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的一些行为,利用系统调用来创建共享内存区域,并设定他的长度并获取共享内存的首地址。然后设定消费者互斥与同步的信号灯,并为他们设置相应的初值。当有消费进程在运行而其他消费者请求时,相应的信号灯就会阻止它,当共享内存区域已空时,信号等也会提示生产者不能再从共享内存中取出相应的内容。 运行的消费者应该与相应的生产者对应起来,只有这样运行结果才会正确。

操作系统实验报告(进程调度算法)

操作系统实验报告(进程调度算法)

实验1 进程调度算法 一、实验内容 按优先数调度算法实现处理器调度。 二、实验目的 在采用多道程序设计的系统中,往往有若干个进程同时处于就绪状态。当就绪进程个数大于处理器数时,就必须依照某种策略来决定哪些进程优先占用处理器。本实验模拟在单处理器情况下的处理器调度,帮助学生加深了解处理器调度的工作。 三、实验原理 设计一个按优先数调度算法实现处理器调度的程序。 (1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表,进程控制块的格式为: 进程名 指针 要求运行时 间 优先数

状态 其中,进程名——作为进程的标识,假设五个进程的进程名分别为P1,P2,P3,P4,P5。 指针——按优先数的大小把五个进程连成队列,用指针指出下一个进程的进程控制块的首地址,最后一个进程中的指针为“0”。 要求运行时间——假设进程需要运行的单位时间数。 优先数——赋予进程的优先数,调度时总是选取优先数大的进程先执行。 状态——可假设有两种状态,“就绪”状态和“结束”状态。五个进程的初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态为“结束”,用“E”表示。 (2) 在每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“优先数”和“要求运行时间”。 (3) 为了调度方便,把五个进程按给定的优先数从大到小连成队列。用一单元指出队首进程,用指针指出队列的连接情况。例: 队首标志 K2

1P1 K 2 P2 K 3 P3 K 4 P4 K 5 P5 0 K4K5K3K1 2 3 1 2 4 1 5 3 4 2 R R R R R PC B1 PC B2 PC B3 PC B4 PC B5 (4) 处理器调度总是选队首进程运行。采用动态改变优先数的办法,进程每运行一次优先数就减“1”。由于本实验是模拟处理器调度,所以,对被选中的进程并不实际的启动运行,而是执行: 优先数-1 要求运行时间-1 来模拟进程的一次运行。 提醒注意的是:在实际的系统中,当一个进程被选中运行时,必须恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行结束。在这里省去了这些工作。

操作系统实验报告(进程的创建)(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);

李建伟版实用操作系统第二版最新习题 3 进程同步与通信

李建伟版实用操作系统第二版最新习题 3 进程同步与通信 一、选择题 题号1 2 3 4 5 6 7 8 9 10 答案A D D C B C A B A A 题号11 12 答案D C 二、综合题 1、答:临界资源也称独占资源、互斥资源,它是指某段时间内只充许一个进程使用的资源。比如打印机等硬件资源,以及只能互斥使用的变量、表格、队列等软件资源。各个进程中访问临界资源的、必须互斥执行的程序代码段称为临界区,各进程中访问同一临界资源的程序代码段必须互斥执行。 为防止两个进程同时进入临界区,可采用软件解决方法或同步机构来协调它们。但是,不论是软件算法还是同步机构都应遵循下述准则: ①空闲让进。②忙则等待。③有限等待。④让权等待。 2、答:忙等待意味着一个进程正在等待满足一个没有闲置处理器的严格循环的条件。因为只有一个CPU 为多个进程服务,因此这种等待浪费了CPU 的时钟。 其他类型的等待:与忙等待需要占用处理器不同,另外一种等待则允许放弃处理器。如进程阻塞自己并且等待在合适的时间被唤醒。忙等可以采用更为有效的办法来避免。例如:执行请求(类似于中断)机制以及PV 信号量机制,均可避免“忙等待”现象的发生。 3、答: 在生产者—消费者问题中,Producer 进程中P(empty)和P(mutex)互换先后次序。先 执行P(mutex),假设成功,生产者进程获得对缓冲区的访问权,但如果此时缓冲池已满,没有空缓冲区可供其使用,后续的P(empty)原语没有通过,Producer 阻塞在信号量empty 上,而此时mutex 已被改为0,没有恢复成初值1。切换到消费者进程后,Consumer 进程执行P(full)成功,但其执行P(mutex)时由于Producer 正在访问缓冲区,所以不成功,阻塞在信号量mutex 上。生产者进程和消费者进程两者均无法继续执行,相互等待对方释放资源,会产生死锁。 在生产者和消费者进程中,V 操作的次序无关紧要,不会出现死锁现象。 4、答:

操作系统原理-进程调度实验报告

一、实验目的 通过对进程调度算法的设计,深入理解进程调度的原理。 进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。 进程调度分配处理机,是控制协调进程对CPU的竞争,即按一定的调度算法从就绪队列中选中一个进程,把CPU的使用权交给被选中的进程。 进程通过定义一个进程控制块的数据结构(PCB)来表示;每个进程需要赋予进程ID、进程到达时间、进程需要运行的总时间的属性;在RR中,以1为时间片单位;运行时,输入若干个进程序列,按照时间片输出其执行序列。 二、实验环境 VC++6.0 三、实验内容 实现短进程优先调度算法(SPF)和时间片轮转调度算法(RR) [提示]: (1) 先来先服务(FCFS)调度算法 原理:每次调度是从就绪队列中,选择一个最先进入就绪队列的进程,把处理器分配给该进程,使之得到执行。该进程一旦占有了处理器,它就一直运行下去,直到该进程完成或因发生事件而阻塞,才退出处理器。 将用户作业和就绪进程按提交顺序或变为就绪状态的先后排成队列,并按照先来先服务的方式进行调度处理,是一种最普遍和最简单的方法。它优先考虑在系统中等待时间最长的作业,而不管要求运行时间的长短。 按照就绪进程进入就绪队列的先后次序进行调度,简单易实现,利于长进程,CPU繁忙型作业,不利于短进程,排队时间相对过长。 (2) 时间片轮转调度算法RR

原理:时间片轮转法主要用于进程调度。采用此算法的系统,其程序就绪队列往往按进程到达的时间来排序。进程调度按一定时间片(q)轮番运行各个进程. 进程按到达时间在就绪队列中排队,调度程序每次把CPU分配给就绪队列首进程使用一个时间片,运行完一个时间片释放CPU,排到就绪队列末尾参加下一轮调度,CPU分配给就绪队列的首进程。 固定时间片轮转法: 1 所有就绪进程按 FCFS 规则排队。 2 处理机总是分配给就绪队列的队首进程。 3 如果运行的进程用完时间片,则系统就把该进程送回就绪队列的队尾,重新排队。 4 因等待某事件而阻塞的进程送到阻塞队列。 5 系统把被唤醒的进程送到就绪队列的队尾。 可变时间片轮转法: 1 进程状态的转换方法同固定时间片轮转法。 2 响应时间固定,时间片的长短依据进程数量的多少由T = N × ( q + t )给出的关系调整。 3 根据进程优先级的高低进一步调整时间片,优先级越高的进程,分配的时间片越长。 多就绪队列轮转法: (3) 算法类型 (4)模拟程序可由两部分组成,先来先服务(FCFS)调度算法,时间片轮转。流程图如下:

操作系统实验_实验1

广州大学学生实验报告 开课学院及实验室:计算机科学与工程实验室 2015年11月11日 实验课 操作系统成绩 程名称 实验项 进程管理与进程通信指导老师陈康民目名称 (***报告只能为文字和图片,老师评语将添加到此处,学生请勿作答***) 进程管理 (一)进程的创建实验 一、实验目的 1、掌握进程的概念,明确进程的含义 2、认识并了解并发执行的实质 二、实验内容 1、编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一 个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。试观察记录屏幕上的显示结果,并分析原因。 2、修改上述程序,每一个进程循环显示一句话。子进程显示'daughter …'及'son ……', 父进程显示'parent ……',观察结果,分析原因。 三、实验步骤 1、编写一段程序,使用系统调用fork( )创建两个子进程。 代码: #include main( ) { int p1,p2; while((p1=fork( ))= = -1); /*创建子进程p1*/ if (p1= =0) putchar('b'); else { while((p2=fork( ))= = -1); /*创建子进程p2*/ if(p2= =0) putchar('c'); else putchar('a'); } } 运行结果:

bca,bac, abc ,……都有可能。 2、修改上述程序,每一个进程循环显示一句话。子进程显示'daughter …'及'son ……',父进程显示'parent ……',观察结果,分析原因。 代码:#include main( ) { int p1,p2,i; while((p1=fork( ))= = -1); /*创建子进程p1*/ if (p1= =0) for(i=0;i<10;i++) printf("daughter %d\n",i); else { while((p2=fork( ))= = -1); /*创建子进程p2*/ if(p2= =0) for(i=0;i<10;i++) printf("son %d\n",i); else for(i=0;i<10;i++) printf("parent %d\n",i); } } 结果:

操作系统实验报告进程调度

五邑大学实验报告 操作系统课程 2016~2017年度第1学期实验题目:进程调度 院系:计算机学院 班级: 140801 学号: 3114002472 姓名:黄凯鑫 任课教师:白明成绩评定:

实验二题目:进程调度 完成日期:2016年12 月11 日 1、实验目的 (1)设计一个有n个进程工行的进程调度程序。每个进程由一个进程控制块(PCB)表示。进程控制块通常应包含下述信息:进程名、进程优先数、进程需要运行的时间、占用CPU的时间以及进程的状态等,且可按调度算法的不同而增删。(2)调度程序应包含2~3种不同的调度算法,运行时可任意选一种,以利于各种算法的分析比较。 (3)系统应能显示或打印各进程状态和参数的变化情况,便于观察诸进程的调度过程 2、实验内容 (1)编制和调试示例给出的进程调度程序,并使其投入运行。 (2)自行设计或改写一个进程调度程序,在相应机器上调试和运行该程序,其功能应该不亚于示例。 (3)直观地评测各种调度算法的性能。 3、算法设计 算法: (1) 优先数法。 进程就绪链按优先数大小从高到低排列,链首进程首先投入运行。每过一个时间片,运行进程所需运行的时间片数减1,说明它已运行了一个时间片,优先数也减3,理由是该进程如果在一个时间片中完成不了,优先级应该降低一级。接着比较现行进程和就绪链链首进程的优先数,如果仍是现行进程高或者相同,就让现行进程继续进行,否则,调度就绪链链首进程投入运行。原运行进程再按其优先数大小插入就绪链,且改变它们对应的进程状态,直至所有进程都运行完各自的时间片数。 (2) 简单轮转法。 进程就绪链按各进程进入的先后次序排列,进程每次占用处理机的轮转时间按其重要程度登入进程控制块中的轮转时间片数记录项(相当于优先数法的优先数记录项位置)。每过一个时间片,运行进程占用处理机的时间片数加1,然后比较占用处理机的时间片数是否与该进程的轮转时间片数相等,若相等说明已到达轮转时间,应将现运行进程排到就绪链末尾,调度链首进程占用处理机,且改变它们的进程状态,直至所有进程完成各自的时间片。 实验源代码: #include #include #include #include

操作系统-进程同步习题

第二章进程同步 一、选择最合适的答案 1. 用P、V操作管理临界区时,信号量的初值一般应定义为()。 A.–1 B.0 C.1 D.任意值 2. 有m个进程共享同一临界资源,若使用信号量机制实现对一临界资源的互斥访问,则信号量的变化范围是()。 A.1至–(m-1) B.1至m-1 C.1至–m D.1至m 3. 在下面的叙述中,正确的是()。 A.临界资源是非共享资源 B.临界资源是任意共享资源 C.临界资源是互斥共享资源 D.临界资源是同时共享资源 4. 对进程间互斥地使用临界资源,进程可以() A.互斥地进入临界区 B.互斥地进入各自的临界区 C.互斥地进入同一临界区 D.互斥地进入各自的同类资源的临界区 5. 设两个进程共用一个临界资源的互斥信号量mutex,当mutex=1时表示()。 A.一个进程进入了临界区,另一个进程等待 B.没有一个进程进入临界区 C.两个进程都进入了临界区 D.两个进程都在等待 6. 设两个进程共用一个临界资源的互斥信号量mutex,当mutex=-1时表示()。 A.一个进程进入了临界区,另一个进程等待 B.没有一个进程进入临界区 C.两个进程都进入了临界区 D.两个进程都在等待 7.当一进程因在记录型信号量S上执行P(S)操作而被阻塞后,S的值为()。 A.>0 B.<0 C.≥0 D.≤0 8.当一进程因在记录型信号量S上执行V(S)操作而导致唤醒另一进程后,S的值为()。 A.>0 B.<0 C.≥0 D.≤0 9.如果信号量的当前值为-4,则表示系统中在该信号量上有()个进程等待。 A.4 B.3 C.5 D.0 10.若有4个进程共享同一程序段,而且每次最多允许3个进程进入该程序段,则信号量的变化范围是()。 A. 3,2,1,0 B. 3,2,1,0,-1 C. 4,3,2,1,0 D. 2,1,0,-1,-2 11.若信号S的初值为2,当前值为-1,则表示有( )个等待进程? A.0 B.1 C.2 D.3 12.如果有三个进程共享同一互斥段,而且每次最多允许两个进程进入该互斥段,则信号量的初值应设置为()。 A. 3 B. 1 C. 2 D. 0 13.并发进程之间() A.彼此无关 B.必须同步 C.必须互斥 D.可能需要同步或互斥

操作系统:进程调度实验报告

设计性实验报告 一、实验目的 1.在Linux下用C语言编程模拟优先级进程调度算法和时间片轮转进程调度算法。 2.为了清楚地观察每个进程的调度过程,每次调度程序应将各个进程的情况显示出来。 二、总体设计(设计原理、设计方案及流程等) 1、优先级进程调度算法 采用动态优先级进程调度算法,其基本思想是每次调度总是把处理机分配给优先级最高的进程,同时在运行过程中进程的优先级随着执行或等待的时间而降低或增加。 在该实验中每个进程用一个进程控制块( PCB)表示。进程控制块包含如下信息:进程号,进程名、优先数、需要运行时间、已用CPU时间、进程状态。进程号,名字,优先数,运行的时间,事先人为地指定。每个进程的状态可以是就绪,执行,阻塞或完成4种状态之一。 就绪进程获得 CPU后都只能运行一个时间片。用已占用CPU时间加1来表示。就绪队列中的进程在等待一个时间片后,优先级增1。如果运行一个时间片后,进程的已占用 CPU时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用CPU时间还未达所需要的运行时间,也就是进程还需要继续运行,此时将进程的优先级减1,然后把它插入就绪队列等待CPU。 2、时间片轮转调度算法 采用简单时间片轮转调度算法,其基本思想是:所有就绪进程按 FCFS排成一个队列,总是把处理机分配给队首的进程,各进程占用CPU的时间片相同。如果运行进程用完它的时间片后还未完成,就把它送回到就绪队列的末尾,把处理机重新分配给队首的进程。直至所有的进程运行完毕。 三、实验步骤(包括主要步骤、代码分析等) 1.打开linux虚拟机,用vim编辑器打开代码进行修改和调整。用gcc编译器进行编译编译运行首先运行优先级算法,如图所示:

进程同步实验报告

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

相关主题
文本预览
相关文档 最新文档