生产者消费者_记录型信号量-c语言描述版本
计算机操作系统第二章课后答案(完整版)

第二章1. 什么是前趋图?为什么要引入前趋图?答:前趋图(Precedence Graph)是一个有向无循环图,记为DAG(Directed Acyclic Graph),用于描述进程之间执行的前后关系。
2. 画出下面四条语句的前趋图:S1=a:=x+y; S2=b:=z+1; S3=c:=a – b; S4=w:=c+1;答:其前趋图为:3. 什么程序并发执行会产生间断性特征?答:程序在并发执行时,由于它们共享系统资源,为完成同一项任务需要相互合作,致使这些并发执行的进程之间,形成了相互制约关系,从而使得进程在执行期间出现间断性。
4.程序并发执行时为什么会失去封闭性和可再现性?答:程序并发执行时,多个程序共享系统中的各种资源,因而这些资源的状态由多个程序改变,致使程序运行失去了封闭性,也会导致其失去可再现性。
5.在操作系统中为什么要引入进程概念?它会产生什么样的影响?答:为了使程序在多道程序环境下能并发执行,并对并发执行的程序加以控制和描述,在操作系统中引入了进程概念。
影响: 使程序的并发执行得以实行。
6.试从动态性,并发性和独立性上比较进程和程序?答:(1)动态性是进程最基本的特性,表现为由创建而产生,由调度而执行,因得不到资源而暂停执行,由撤销而消亡。
进程有一定的生命期,而程序只是一组有序的指令集合,是静态实体。
(2)并发性是进程的重要特征,同时也是OS 的重要特征。
引入进程的目的正是为了使其程序能和其它进程的程序并发执行,而程序是不能并发执行的。
(3)独立性是指进程实体是一个能独立运行的基本单位,也是系统中独立获得资源和独立调度的基本单位。
对于未建立任何进程的程序,不能作为独立单位参加运行。
7.试说明PCB 的作用,为什么说PCB 是进程存在的惟一标志?答:PCB 是进程实体的一部分,是操作系统中最重要的记录型数据结构。
作用是使一个在多道程序环境下不能独立运行的程序,成为一个能独立运行的基本单位,成为能与其它进程并发执行的进程。
操作系统复习资料

1什么是操作系统及四个基本特征操作系统是一组控制和管理计算机硬件和软件资源,合理地对各类作业进行调度,以及方便用户使用的程序的集合。
P9操作系统的四个基本特征是并发、共享、虚拟和异步。
P142操作系统的主要功能,什么是分时操作系统操作系统的主要功能:处理机管理、存储器管理、设备管理和文件管理p18分时操作系统是指,在一台主机上连接了多个带有显示器和键盘的终端,同时允许多个用户通过主机的终端,以交互方式使用计算机,共享主机中的资源。
P103操作系统的接口有几种类型用户与操作系统的接口通常可分为两大类:1用户接口。
它是提供给用户使用的接口,用户可通过该接口取得操作系统的服务2程序接口。
它是提供给程序员在编程时使用的接口,是用户程序取得操作系统的唯一途径p224 在OS为什么要引入进程的概念,为什么要引入线程为了使程序在多道程序环境下能并发执行,并能对并发执行的程序加以控制和描述,而引入了进程概念。
P37在操作系统中引入线程,是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性。
P725进程控制块是什么?作用及构成为了使程序(含数据)能独立运行,应为之配置一进程控制块,即PCB(Process Control Block);PCB是进程实体的一部分,是操作系统中最重要的记录型数据结构,PCB中记录了操作系统所需的用于描述进程情况及控制进程运行所需的全部信息。
在进程控制块中,主要包括下述四方面的信息。
1进程标示符2处理机状态3进程调度信息4进程控制信息因而它的作用是使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位,一个能和其他进程并发执行的进程。
P416进程的基本状态有哪些?进程实体是由什么组成的进程执行时的间断性决定了进程可能具有多种状态。
事实上,运行中的进程可能具有以下三种状态。
1就绪状态2执行状态3阻塞状态p38由程序段、相关的数据段和PCB三部分便构成了进程实体。
经典进程的同步问题之——生产者消费者

经典进程的同步问题之——⽣产者消费者1 、利⽤记录型信号量解决⽣产者——消费者问题假定在⽣产者和消费者之间的公⽤缓冲池,具有n个缓冲区,这时可利⽤互斥信号量mutex实现诸进程对缓冲池的互斥使⽤。
利⽤信号量empty和full分别表⽰缓冲池中空缓冲区和满缓冲区的数量。
只要缓冲区未满⽣产者便可将消息送⼊缓冲区,只要缓冲区未空消费者便可从缓冲区取⾛⼀个消息。
1 Var mutex,empty,full:semapthore:=1,n,0; // 声明互斥信号量mutex=1,n个空缓冲区,满缓冲区个数为02 buffer:array[0,1,...,n-1] of item;3in,out:integer:=0,0; // 输⼊、输出指针4 begin5 parbegin6 proceducer:begin7 repeat8 ...9 proceducer an item nextp; // ⽣产⼀个产品10 ...11 wait(empty); // 申请⼀个空缓冲区12 wait(mutex); // 申请⼀个临界资源使⽤权13 buffer(in):=nextp;// 将产品放⼊缓冲池中14in:=(in+1) mod n; // 输⼊指针向前移⼀个位置15 signal(mutex); // 释放临界资源16 signal(full); // 释放⼀个满缓冲区17 until false;18 end19 consumer:begin20 repeat21 wait(full); // 申请⼀个满缓冲区22 wait(mutex); // 申请⼀个临界资源使⽤权23 nextc:=buffer(out); // 从缓冲池取⾛⼀个产品24out:=(out+1) mod n; // 输出指针向前移⼀个位置25 signal(mutex); // 释放临界资源26 signal(empty); // 释放⼀个空缓冲区27 consumer the item in nextc;28 until false29 end30 parend31 end2、利⽤AND信号量解决⽣产者——消费者问题(看懂了上⾯的详细分析,下⾯的伪代码就容易理解多了)1 Var mutex,empty,full:semapthore:=1,n,0;2 buffer:array[0,...,n-1] of item;3in out:integer:=0,0;4 begin5 parbegin6 proceducer:begin7 repeat8 ...9 proceduce an item in nextp;10 ...11 Swait(empty,mutex); // 同时申请⼀个空缓冲区和临界资源使⽤权12 buffer(in):=nextp;13in:=(in+1)mod n;14 Ssignal(mutex,full); // 同时释放⼀个临界资源和满缓冲区15 until false16 end17 consumer:begin18 repeat19 Swait(full,mutex);20 Nextc:=buffer(out);21 Out:=(out+1)mod n;22 Ssignal(mutex,empty);23 consumer the item in nextc;24 until false;25 end26 parend27 end。
多线程:生产者消费者(管程法、信号灯法)

2、管程法(1)创建⽣产者:多线程:⽣产者消费者(管程法、信号灯法)1、⽣产者、消费者(2)创建消费者:(3)创建产品类:(4)创建同步代码:public class Consume extends Thread {SynContainer synContainer;public Consume(SynContainer synContainer){this .synContainer=synContainer;}public void run(){for (int i=0;i<10;i++){System.out.println("消费了第"+i+"只鸡");}}}public class Chicken {int id;public Chicken(int id) {this .id=id;}}public class SynContainer {Chicken[] chickens =new Chicken[10];//容器计数器int count=0;//⽣产者⽣产产品public synchronized void push(Chicken chicken){//如果容器满了,就需要等待消费的消费if (count==chickens.length){//通知消费者消费try {this .wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果没有满就需要丢⼊产品chickens[count]=chicken;count ++;this .notifyAll();}public synchronized Chicken pop(){//判断能否消费if (count==0){try {this .wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果可以消费,就消费count--;Chicken chicken=chickens[count];//吃完了,通知⽣产者⽣产this.notifyAll();return chicken;}}保证容器中没有产品的时候⽣产产品,不能消费;容器中产品满了的时候,不能再去⽣产产品(5)创建测试类:public class Test {public static void main(String[] args) {SynContainer synContainer=new SynContainer();new Productor(synContainer).start();new Consume(synContainer).start();}}(6)测试:⽣产了0只鸡⽣产了1只鸡⽣产了2只鸡⽣产了3只鸡⽣产了4只鸡⽣产了5只鸡⽣产了6只鸡⽣产了7只鸡⽣产了8只鸡⽣产了9只鸡消费了第0只鸡消费了第1只鸡消费了第2只鸡消费了第3只鸡消费了第4只鸡消费了第5只鸡消费了第6只鸡消费了第7只鸡消费了第8只鸡消费了第9只鸡3、信号灯法(1)创建⽣产者://⽣产者:演员public class Player extends Thread {TV tv;public Player(TV tv){=tv;}public void run(){for (int i = 0; i < 20; i++) {if(i%2==0){.play("猫和⽼⿏");}else {.play("海绵宝宝");}}}}(2)创建消费者://消费者:观众public class Watcher extends Thread {TV tv;public Watcher(TV tv){=tv;}public void run(){for (int i = 0; i < 20; i++) {tv.watch();}}}(3)书写同步代码://产品:节⽬public class TV {//演员表演,观众等待//观众观看,演员等待String voice;//表演的节⽬boolean flag=true;//表演public synchronized void play(String voice){if(!flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("演员表演了:"+voice);//通知观众观看this.notifyAll();//唤醒this.voice=voice;this.flag=!this.flag;}//观看public synchronized void watch(){if(flag){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("观看了"+voice);//通知演员表演this.notifyAll();this.flag=!this.flag;}}(4)创建测试类://通过标志位解决public class Test {public static void main(String[] args) {TV tv=new TV();new Player(tv).start();new Watcher(tv).start();}}(5)测试:演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝演员表演了:猫和⽼⿏观看了猫和⽼⿏演员表演了:海绵宝宝观看了海绵宝宝(6)与管程法的最⼤不同就是,⽤信号灯法需要设置⼀个标志位,⽽管程法是设置⼀个变量,根据变量的值来进⾏。
操作系统之生产者消费者问题(C 实现)

/*----------------------把新生产的产品放入缓冲区开------------------------*/
//把新生产的产品放入缓冲区 void Append() { std::cerr<<"把生产的产品送入缓冲区";
g_buffer[in]=ProductID; in=(in+1)%SIZE_OF_BUFFER; std::cerr<<std::endl; std::cout<<"缓冲区 产品 生产者/消费者"<<std::endl;
{
if(g_buffer[i]<10) std::cout<<" "; else std::cout<<" "; std::cout<<" <-- 生产者";//输出生产者的指针位置 } if(i==out) { if(g_buffer[i]<10) std::cout<<" "; else std::cout<<" "; std::cout<<" <-- 消费者";//输出消费者的指针位置 } std::cout<<std::endl; } } /*----------------------把新生产的产品放入缓冲区结------------------------*/
(算法流程图、编程及程序注释等)
主要的方法:
4、运行结果分析 1、运行示例 在 c++中运行源程序 ,程序主界面截图.按回车及申请资源和缓冲区进行 p 操作 和申请互斥(生产者和消费者都是 2
操作系统之生产者消费者问题(c++实现)

{
std::cout<<"* - - - - - - - - - - - - - - - - - - - - - - - *"<<std::endl;
std::cout<<"|课程设计课题:生产者-消费者问题的模拟实现|"<<std::endl;
std::cout<<"|指导老师:李先锋|"<<std::endl;
bool g_continue = 1;//控制程序运行:1表示继续运行?0表示停止运行
HANDLE g_hMutex;//线程间的互斥信号量
HANDLE g_hFullSemaphore;//资源信号量:缓冲区满
HANDLE g_hEmptySemaphore;//资源信号量:缓冲区空
DWORD WINAPI Producer(LPVOID);//生产者线程
std::cout<<"|学生:丁可|"<<std::endl;
std::cout<<"|班级: B计123班|"<<std::endl;
std::cout<<"* - - - - - - - - - - - - - - - - - - - - - - - *"<<std::endl;
std::cout<<" ==》按回车开始该程序"<<std::endl;
getchar();
}
/*----------------------------程序提示信息结束------------------------------*/
第2章 进程管理课后习题解答

第题中,如果修改问题中的同步算法,要求 对写进程优先,即一旦写进程到达,后续的读者进程必须等待, 而无论是否有读者进程在读文件。写出相应进程的程序段。 semaphore fmutex=1, rmutex=1, wmutex=1;que=1;
int rcount=0, wcount=0; void main() { parbegin(reader, writer); }
12
void reader { while(1) { wait(que); wait(rmutex); if(0==readcount) wait(fmutex); readcount++; signal(rmutex); signal(que); …. begin to read wait(rmutex); readcount--; if(readcount==0) signal (fmutex); signal(rmutex); } }
读者—写者问题(读优先) 读者 写者问题(读优先) 写者问题 semaphore rmutex=1,wmutex=1; int readcount=0; = void main() { parbegin(reader,writer); }
读者进程: 读者进程: void reader() { while(1) { wait(rmutex); if (readcount==0) wait(wmutex); readcount++; signal(rmutex); … 读操作 wait(rmutex); readcount--; if (readcount==0) signal(wmutex); signal(rmutex); } }
18
chopstick[ ={1 semaphore chopstick[5]={1,1,1,1,1}; viod main() { parbegin(P0(),P1(),P2(),P3(),P4()); parbegin(P0(),P1(),P2(),P3(),P4()); } Pi() /*i=0,1,2,3,4*/ { while(1) { wait(chopstick[i]); [ ] wait(chopstick[(i+1)%5]); [ ] eating; … signal(chopstick[i]); [ ] signal(chopstick[(i+1) %5]); [ ] thinking; } }
0714-----C++Primer听课笔记----------生产者消费者模型(C语言版)

0714-----C++Primer听课笔记----------⽣产者消费者模型(C语⾔版)1. 程序⼀,错误之处,当⼀个消费者在等待,此时⼀个⽣产者⽣产⼀个产品后把该消费者的等待线程激活,但是此时她还没有抢到锁,这个时候⼜来了⼀个消费者,并且互斥锁正好被它抢⾛,那么经过if判断此时队列不空,新来的消费者消费完释放锁离开,这时前⾯的被激活的那个消费者抢到了锁,当它在进⾏消费的时候就发⽣了错误,因为这个时候队列时空的。
程序如下:#include "queue.h"#include <pthread.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#define BUF_SIZE 3pthread_mutex_t mutex; // 互斥锁保护队列pthread_cond_t full; //同步量有产品可取pthread_cond_t empty; //同步量有空位可放Queue Q;void *producer(void* arg){while(1){pthread_mutex_lock(&mutex);if(Q.size_ == BUF_SIZE){pthread_cond_wait(&empty, &mutex);}int data = rand()%100;printf("produce a %d\n", data);queue_push(&Q, data);pthread_cond_signal(&full);pthread_mutex_unlock(&mutex);}}void *consumer(void* arg){while(1){pthread_mutex_lock(&mutex);if(queue_is_empty(&Q)){printf("wait for producer\n");pthread_cond_wait(&full, &mutex);}int data = queue_top(&Q);printf("consume a %d\n", data);queue_pop(&Q);pthread_cond_signal(&empty);pthread_mutex_unlock(&mutex);}}int main(int argc, const char *argv[]){srand(100000);pthread_t tid1, tid2, tid3;pthread_mutex_init(&mutex, NULL);pthread_cond_init(&full, NULL);pthread_cond_init(&empty, NULL);queue_init(&Q);pthread_create(&tid3, NULL, producer, NULL);pthread_create(&tid1, NULL, consumer, NULL);pthread_create(&tid2, NULL, consumer, NULL);queue_destroy(&Q);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&full);pthread_cond_destroy(&empty);return0;}2.程序⼆,将上例中的if改为while循环,这样,当等待线程被唤醒时,若抢到锁,会再次检查⼀下当前队列是否为空,若为空,则⼜进⼊等待状态,否则⽅可取⾛产品,这样就有效消除了上述错误。