生产者消费者问题操作系统课程设计

生产者消费者问题操作系统课程设计
生产者消费者问题操作系统课程设计

课程设计报告

课程名称:操作系统

专业____________ 计算机科学与技术__________ 学生姓名____________________________________ 班级_______________________________________ 学号_______________________________________ 指导教师____________________________________ 完成日期___________________________________

信息工程学院

题目:生产者-消费者问题的模拟实现

一、设计目的

本课程设计是学习完“操作系统原理”课程后进行的一次全面的综合训练,通过课程设计,更好地掌握操作系统的原理及实现方法,加深对操作系统基础理论和重要算法的理解,加强学生的动手能力。

二、设计内容

(1)概述

设计目的:通过研究Linux的进程机制和信号量实现生产者消费者问题的并发控制。

说明:有界缓冲区内设有20个存储单元,放入/取出的数据项设定为1-20这20个整型数。

设计要求:(1)每个生产者和消费者对有界缓冲区进行操作后,即时显示有界缓冲区的全部内容,当前指针位置和生产者/消费者县城的标识符。(2)生产者和消费者各有两个以上。(3)多个生产者或多个消费者之间须有共享对缓冲区进行操作的函数代码。

(2)设计原理

通过一个有界缓冲区把生产者和消费者联系起来。假定生产者和消费者的优先级是相同的,只要缓冲区未满,生产者就可以生产产品并将产品送入缓冲区。类似地,只要缓冲区未空,消费者就可以从缓冲区中取走产品。应该禁止生产者向满的缓冲区送入产品,同时也应该禁止消费者从空的缓冲区中取出产品,这一机制有生产者线程和消费者线程之间的互斥关系来实现。与计算打印两进程同步关系相同,生产者和消费者两进程P和C之间应满足下列两个同步条件:

①只有在缓冲池中至少有一个缓冲区已存入消息后,消费者才能从中提取信息,

否则消费者必须等待。

②只有缓冲池中至少有一个缓冲区是空时,生产者才能把消息放入缓冲区,否则生产者必

须等待。

为了满足第一个同步条件,设置一个同步信号量full,它代表的资源是缓冲区满,

它的初始值为0,它的值为n时整个缓冲池满。这个资源是消费者类进程C所有,C进

程可以申请该资源,对它施加P操作,而C进程的合作进程生产者进程P对它施加V操作。同样为了满足第二个同步条件,设置另一个同步信号量empty,它代表的资源是缓

冲空区,它的初始值为n,表示缓冲池中所有缓冲区空。信号量full表示可用缓冲区数量,信号

量empty表示缓冲区数量,设置整型变量:存入指针in和取出指针out。

为解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的

数目,用g_hFullSemaphore表示,其初始值为有界缓冲区的大小SIZE_OF_BUFFEF另一个表示缓冲区中产品的数目,用g_hEmptySemaphore表示,其初始值为0.另外,由于有界缓冲区是一个临界资源,必须互斥使用,所以还需要在设置一个互斥信号量g_hMutex,初始值为1.

P原语的主要动作是:

①sem减1 ;

②若sem减一后仍大于或等于零,则进程继续执行;

③若sem减一后小于零,则该进程被阻塞后入与该信号相对应的队列

中,然后转进程调度。

V原语的操作主要动作是:

①sem加1 ;

②若相加结果大于零,进程继续执行;

③若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程

然后再返回原进程继续执行或转进程调度。

采用的同步方法:

1)利用函数CreateMutex(NULL,FALSE,NULL创建互斥信号量g_hMutex,表

示缓冲区当前的状态,若为true时,则表示缓冲区正被别的进程使用。三个参

数表示的意义分别为:指向安全属性的指针,初始化互斥对象的所有者,指向互

斥对象名的指针。

2)利用函数CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1, NULL创建缓冲区满的信号量g_hFullSemaphore,值为true时表示缓冲区已满。四个参数分别为:表示是否允许继承、设置信号机的初始计数、设置信号机的最

大计数、指定信号机对象的名称(-1是因为计数从开始)。

3) 利用函数CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NUL创建缓冲区空的信号量g_hEmptySemaphore该值为true时表示缓冲区为空。

5、数据定义及其详细解释

const un sig ned short SIZE_OF_BUFFER = 20; //

DWORD WINAPI Producer(LPVOID); //

DWORD WINAPI Con sumer(LPVOID); // 消费者线程

(3)详细设计及编码

流程图缓冲区长度

un sig ned s hort ProductID = 0; // un sig ned s hort Co nsumelD = 0; // un sig ned s hort in = 0; //

un sig ned s hort out = 0; //

int g_buffer[SIZE_OF_BUFFER]; // bool g_continue = true; //

HANDLE g_hMutex; // HANDLE g_hFullSemaphore; // HANDLE g_hEmptySem aphore; //

产品号

将被消耗的产品号

产品进缓冲区时的缓冲区下标

产品出缓冲区时的缓冲区下标

缓冲区是个循环队列

使程序跳出循环,控制程序结

用于线程间的互斥

当缓冲区满时迫使生产者等待

当缓冲区空时迫使消费者等待生产者线程

消费者:

程序清单

1. 存储结构定义

利用信号量解决生产者消费者问题

const un sig ned short

SIZE_OF_BUFFER = 10; // 缓冲区长

度 un sig ned short ProductID = 0;

//

un sig ned short Con sumeID = 0; // un sig ned short in = 0; // un sig ned short out = 0; //

in t

g_buffer[SIZE_OF_BUFFER]; bool g_continue = true; // HANDLE g_hMutex;

HANDLE g_hFullSem aphore; // HANDLE g_hEmptySem aphore; //

DWORD WINAPI Producer(LPVOID); // 生产者线程 DWORD WINAPI Con sumer(LPVOID); // 消费者线程 2. 算法相关的函数

(1)创建各个互斥信号以及生产者线程和消费者线程的函数在如下主函数里面 所示:

产品号

将被消耗的产品号

产品进缓冲区时的缓冲区下标 产品出缓冲区时的缓冲区下标 缓

冲区是个循环队列

控制程序结束 用于线程间的互斥

当缓冲区满时迫使生产者等待 当缓冲区空时迫使消费者等待

// //

入口

int main()

{

//创建各个互斥信号

g_hMutex = CreateMutex(NULL,FALSE,NULL);

g_hFullSemaphore

CreateSemaphore(NULL,SIZE_OF_BUFFER-1,SIZE_OF_BUFFER-1,NULL);

g_hEmptySemaphore = CreateSemaphore(NULL,0,SIZE_OF_BUFFER-1,NULL); //调整下面的数值,可以发现,当生产者个数多于消费者个数时,

//生产速度快,生产者经常等待消费者;反之,消费者经常等待。

const un sig ned short PRODUCERS_COUNT = 3; // 生产者的个数

const un sig ned short CONSUMERS_COUNT = 1; // 消费者的个数

//总的线程数

const un sig ned short THREADS_COUNT

PRODUCERS_COUNT+CONSUMERS_COUNT;

HANDLE hThreads[PRODUCERS_COUNT]; // 各线程的handle

DWORD producerID[CONSUMERS_COUNT]; // 生产者线程的标识符DWORD con sumerlD[THREADS_COUNT]; // 消费者线程的标识符

// 创建生产者线程

for (i nt i=0;i {

hThreads[i]=CreateThread(NULL,0,Producer,NULL,0,&producerlD[i]);

if (hThreads[i]==NULL)

return -1;

}

//创建消费者线程

for ( i=0;i {

hThreads[PRODUCERS_COUNT+i]=CreateThread(NULL,0,Co nsumer,NULL,0 &con sumerID[i]);

if (hThreads[i]==NULL)

return -1;

}

while(g_co nti nue)

{

if(getchar())

{ // 按回车后终止程序运行

g_continue = false; }}

return 0; }

(2)生产者生产一个产品的函数:

//生产一个产品。简单模拟了一下,仅输出新产品的void

ID号

Produce。

{

std::cerr << "Producing " << ++ProductlD << " *** "; std::cerr << "Succeed" << std::e ndl;

}

(3)把新生产的产品放入缓冲区的函数:

//把新生产的产品放入缓冲区

void Appe nd()

{

std::cerr << "Appe nding a product *** ";

g_buffer[i n] = ProductID;

in = (in+1)%SIZE_OF_BUFFER;

std::cerr << "Succeed" << std::e ndl;

}

(4)输出缓冲区当前的状态的函数:

//输出缓冲区当前的状态

for (i nt i=0;i {

std::cout << i <<": " << g_buffer[i];

if (i==in)

std::cout << " <-- 生产";

if (i==out)

std::cout << " <-- 消费";

std::cout << std::e ndl;

}

从缓冲区中取出一个产品的函数:

//从缓冲区中取出一个产品

void Take()

{

相关主题
相关文档
最新文档