当前位置:文档之家› 操作系统实验报告生产者消费者问题

操作系统实验报告生产者消费者问题

操作系统课程设计一.实验目标完成N个生产者和M个消费者线程之间的并发控制,N、M不低于30,数据发送和接收缓冲区尺寸不小于20个(每个产品占据一个)。

其中生产者线程1、3、5、7、9生产的产品供所有奇数编号的消费者线程消费,只有所有奇数编号的消费者线程都消费后,该产品才能从缓冲区中撤销。

其中生产者线程2、4、6、8、10生产的产品所有偶数编号的消费者线程都可消费,任一偶数编号消费者线程消费该消息后,该产品都可从缓冲区中撤销。

其中11-20号生产者线程生产的产品仅供对应编号的消费者线程消费。

其他编号生产者线程生产的产品可由任意的消费者线程消费。

每个生产线程生产30个消息后结束运行。

如果一个消费者线程没有对应的生产者线程在运行后,也结束运行。

所有生产者都停止生产后,如果消费者线程已经没有可供消费的产品,则也退出运行。

二.实验原理2.1原理生产者与消费者线程采用posix互斥锁机制进行互斥进入各自的代码段,只有采用互斥锁临界区代码段才可以不被打扰的执行;同步机制采用的是posix条件变量pthread_cond_wait和pthraed_cond_signal进行同步的。

线程间的通信采用的是共享内存机制。

(注:所有的共享内存块是在进程里建立的,线程只需链接上各自的共享内存块即可,每一块共享内存的大小是100). 在这里共享内存设置成一个100的数组。

具体实施:(1)为1.3.5.7.9建立一个共享内存1号,1.3.5.7.9生产者线程生产的产品都放入这块共享内存缓冲区,所有奇数的消费者线程要消费的话,只需在消费者线程中链接上这块共享内存,就可以直接消费1.3.5.7.9生产者线程生产的产品。

(2)为2.4.6.8.10建立一块共享内存2号。

2.4.6.8.10生产的产品都放入2号共享内存缓冲区,所有的偶数的消费者线程只要链接上2号缓冲区,就可以消费2.4.6.8.10生产的产品。

当偶数消费者线程消费产品后,产品即可从缓冲区撤销,方法是在消费线程里将消费的产品在共享内存数组里置0。

(3)为11--20的每一对生产者消费者线程建立一块共享内存,编号11--20. 11--20号的消费者线程能链接各自的共享内存缓冲区或奇数或偶数共享内存缓冲区,即11--20号的生产者生产的产品只能被对应的消费者消费而11-20的奇数消费者可以消费缓冲区1的产品,偶数消费者可消费缓冲区2的产品。

(4)为21--30号的生产者消费者线程只建立一块共享内存21号,21--30号生产者生产的产品都放入21号缓冲区,所有的消费者线程只要链接上21号共享内存,就可以消费21--30号生产者生产的产品。

用于控制线程是否结束的方法是:设置一个全局变量t,在生产者线程里进行t++,在生产者线程里当t达到10时(注:为了很好的测试程序,本应该在生产者生产30个产品时菜结束线程,这里设置成了10),就break跳出while()循环,这样线程自然就终止。

同样在消费者线程里,当t达到10时,这里不用t++,就跳出while()循环,消费者线程自然就终止。

这样设计满足了,当生产者生产30个产品时就终止生产者线程,生产者线程终止消费者线程也得终止的要求。

生产者从文件so.txt读取数据进行生产,这个文件里的数据是一连串的字符从a--z的组合,没有空格或其他字符。

文件内容的格式没有特殊要求。

2.2函数说明创建线程函数:参数tida30是线程号,produce30是线程30生产者函数。

消费者线程其他线程与以上的两个线程函数功能一样,只是变量不同。

等待函数,当满足一定条件时就会阻塞线程,而激活另一个线程触发函数,当满足一定条件时就会激活一个线程建立共享内存函数:在进程里创建一块共享内存链接共享内存函数:参数shmid19是共享内存标识号,此函数将线程连接到指定的共享内存。

三.实验设计3.1设计方案通过一个有界缓冲区(用数组来实现,类似循环队列)把生产者和消费者联系起来。

假定生产者和消费者的优先级是相同的,只要缓冲区未满,生产者就可以生产产品并将产品送入缓冲区。

类似地,只要缓冲区未空,消费者就可以从缓冲区中去走产品并消费它。

应该禁止生产者向满的缓冲区送入产品,同时也应该禁止消费者从空的缓冲区中取出产品,这一机制有生产者线程和消费者线程之间的互斥关系来实现。

为解决生产者/消费者问题,应该设置两个资源信号量,其中一个表示空缓冲区的数目,用g_hFullSemaphore表示,其初始值为有界缓冲区的大小SIZE_OF_BUFFER;另一个表示缓冲区中产品的数目,用g_hEmptySemaphore表示,其初始值为0。

另外,由于有界缓冲区是一个临界资源,必须互斥使用,所以还需要再设置一个互斥信号量g_hMutex,起初值为1。

在生产者/消费者问题中,信号量实现两种功能。

首先,它是生产产品和消费产品的计数器,计数器的初始值是可利用的资源数目(有界缓冲区的长度)。

其次,它是确保产品的生产者和消费者之间动作同步的同步器。

生产者要生产一个产品时,首先对资源信号量g_hFullSemaphore 和互斥信号量g_hMutex 进行P 操作,申请资源。

如果可以通过的话,就生产一个产品,并把产品送入缓冲区。

然后对互斥信号量g_hMutex 和资源信号量g_hEmptySemaphore 进行V 操作,释放资源。

消费者要消费一个产品时,首先对资源信号量g_hEmptySemaphore 和互斥信号量g_hMutex 进行P 操作,申请资源。

如果可以通过的话,就从缓冲区取出一个产品并消费掉。

然后对互斥信号量g_hMutex 和资源信号量g_hFullSemaphore 进行V 操作,释放资源。

如果缓冲区中已经没有可用资源,就把申请资源的进程添加到等待队列的队尾。

如果有一个资源被释放,在等待队列中的第一个进程被唤醒并取得这个资源的使用权。

3.2详细设计 生产者produce () 流程图:开始链接共享内存打开文件Count++,t++t=1进入临界区是否是消费者comsume()流程图:开始选择消费缓冲区,链接共享内存Count--t=11进入临界区Count=0阻塞消费者线程,激活生消费产品否是是否否实现思路:在main里创建30对线程,30个生产者,30个消费者。

每对生产者消费者线程对应一对生产者消费者函数produce()和comsume();生产者函数的实现:先链接对应的共享内存缓冲区,打开文件;设置全局变量count用于控制生产者线程的阻塞与消费者线程激活。

当count=4时,意味着生产者生产了3个产品但是消费者没有消费,这时调用pthread_cond_wait()函数阻塞生产者线程,激活消费者线程消费。

当count=1时,意味着生产者生产了一个产品消费者没有消费掉,就调用pthread_cond_signal()函数激活消费者线程消费。

设置全局变量t,用于控制线程是否结束。

当t=11时,意味着生产者生产了10个产品,此时调用break跳出while循环,终止生产者线程。

采用posix 互斥锁机制进行互斥进入各自的代码段,只有采用互斥锁临界区代码段才可以不被打扰的执行;同步机制采用的是posix条件变量pthread_cond_wait和pthraed_cond_signal进行同步的。

消费者函数的实现:先链接对应的共享内存缓冲区;设置全局变量t与生产者的功能一样,在此不作介绍。

设置全局变量count,用于控制消费者的阻塞与生产者线程的激活,当count=0时,调用pthread_cond_wait()函数阻塞消费者线程并激活生产者线程进行生产;当count<3时,调用pthread_cond_signal()函数激活生产者线程进行生产。

采用posix互斥锁机制进行互斥进入各自的代码段,只有采用互斥锁临界区代码段才可以不被打扰的执行;同步机制采用的是posix条件变量pthread_cond_wait和pthraed_cond_signal进行同步的。

线程间的通信采用的是共享内存机制。

(注:所有的共享内存块是在进程里建立的,线程只需链接上各自的共享内存块即可,每一块共享内存的大小是100). 在这里共享内存设置成一个100的数组。

具体实施:(1)为1.3.5.7.9建立一个共享内存1号,1.3.5.7.9生产者线程生产的产品都放入这块共享内存缓冲区,所有奇数的消费者线程要消费的话,只需在消费者线程中链接上这块共享内存,就可以直接消费1.3.5.7.9生产者线程生产的产品。

(2)为2.4.6.8.10建立一块共享内存2号。

2.4.6.8.10生产的产品都放入2号共享内存缓冲区,所有的偶数的消费者线程只要链接上2号缓冲区,就可以消费2.4.6.8.10生产的产品。

当偶数消费者线程消费产品后,产品即可从缓冲区撤销,方法是在消费线程里将消费的产品在共享内存数组里置0。

(3)为11--20的每一对生产者消费者线程建立一块共享内存,编号11--20. 11--20号的消费者线程能链接各自的共享内存缓冲区或奇数或偶数共享内存缓冲区,即11--20号的生产者生产的产品只能被对应的消费者消费而11-20的奇数消费者可以消费缓冲区1的产品,偶数消费者可消费缓冲区2的产品。

(4)为21--30号的生产者消费者线程只建立一块共享内存21号,21--30号生产者生产的产品都放入21号缓冲区,所有的消费者线程只要链接上21号共享内存,就可以消费21--30号生产者生产的产品。

线程的终止是靠全局变量t实现的,在produce()函数里进行t++,当t=11即生产了10个产品时,就跳出while循环终止生产者线程,生产者线程终止时消费者函数里的t=11也跳出while循环终止消费者线程。

也就是当生产者线程终止时消费者线程也就终止了。

重要代码注释:四.实验测试(注:测试时在选择消费缓冲区时,必须快速输入缓冲区代号,然后快速按enter键)由于这里没有开启21--30号线程,所以缓冲区只能选择一号。

同一线程号的一对生产者消费者线程比较集中,这是由于同步机制完成的任务。

1 3 5 7 9公用一个共享内存缓冲区,生产者生产的产品都放入这块缓冲区,奇数号的消费者线程竞争消费缓冲区里的产品。

从图中可看到,越往后1 3 等的线程已--经不见了,说明生产者已经生产了10个产品后生产者线程和消费者线程自行终止了。

缓冲区里的产品已经列出如图所示。

由于这里没有开启21--30号线程,所以缓冲区只能选择二号。

同一线程号的一对生产者消费者线程比较集中,这是由于同步机制完成的任务。

2 4 6 8 10公用一块共享内存缓冲区,生产者生产的产品都放入这块缓冲区,偶数号的消费者线程竞争消费缓冲区里的产品。

相关主题