生产者消费者_记录型信号量-c语言描述版本
- 格式:doc
- 大小:27.50 KB
- 文档页数:1
第二章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)与管程法的最⼤不同就是,⽤信号灯法需要设置⼀个标志位,⽽管程法是设置⼀个变量,根据变量的值来进⾏。
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循环,这样,当等待线程被唤醒时,若抢到锁,会再次检查⼀下当前队列是否为空,若为空,则⼜进⼊等待状态,否则⽅可取⾛产品,这样就有效消除了上述错误。
P 、V一、生产者--消费者问题(采用信号量机制)Consumer Producer P(empty);P(mutex);//进入区 one unit --> buffer;V(mutex);V(full);//退出区P(full);P(mutex);//进入区 one unit <-- buffer;V(mutex);V(empty);//退出区full 是"满"数目,初值为0,empty 是"空"数目,初值为N 。
实际上,full + empty == N;mutex 用于访问缓冲区时的互斥,初值是1;每个进程中各个P 操作的次序是重要的:先检查资源数目,再检查是否互斥――否则可能死锁;Var mutex,empty,full:semaphore:=1,n,0; buffer:array[0,.....n-1];in,out:integer:=0,0; begin parbegin 生产者:beginrepeat生产一个产品nextp; P(empty); P(mutex);将产品输入到buffer 中buffer[in]:=nextp; in=(in+1)mod n; V(mutex); V(full); until false; end; 消费者:beginrepeat P(full); P(mutex);从buffer 中取一个产品 nextc=buffer[out]; out:=(out+1) mod n; V(mutex); V(empty); until false; end;parend; end;三、读者--写着问题(采用信号量机制) 第一类:读者优先如果读者来:1)无读者、写者,新读者可以读2)有写者等,但有其它读者正在读,则新读者也可以读3)有写者写,新读者等 如果写者来:1)无读者,新写者可以写2)有读者,新写者等待3)有其它写者,新写者等待Wmutex 表示"允许写",初值是1。
操作系统生产者消费者代码c++语言操作系统是计算机系统中极为重要的一个组成部分,它负责管理计算机硬件和软件资源,为用户和应用程序提供高效的运行环境。
生产者消费者问题是操作系统中经典的一个并发控制问题,它涉及到多个线程之间的合作与协调。
生产者消费者问题的场景通常是一个缓冲区(也可以称为仓库)和两类线程,即生产者线程和消费者线程。
生产者线程负责向缓冲区中生产产品,而消费者线程则负责从缓冲区中消费产品。
这两类线程必须互相合作,保证生产者线程不会在缓冲区已满时继续生产,消费者线程不会在缓冲区为空时继续消费,以避免数据不一致性的问题。
解决生产者消费者问题的常用方法是使用互斥锁和条件变量。
互斥锁(Mutex)用于保护对缓冲区的访问,当某个线程希望访问缓冲区时,需要先获取互斥锁,其他线程必须等待该线程释放锁后才能进行访问。
条件变量(Condition Variable)用于实现线程间的信号通知机制,当某个线程生产了一个产品并将其放入缓冲区后,需要通知消费者线程可以开始消费了,而当消费者线程消费完一个产品后,需要通知生产者线程可以继续生产。
下面是一个简单的C++代码示例:```cppinclude<iostream>include<queue>include<pthread.h>using namespace std;queue<int>buffer;pthread_mutex_t mutex;pthread_cond_t full_cond,empty_cond;void*producer(void*arg){while(true){pthread_mutex_lock(&mutex);while(buffer.size()>=10){pthread_cond_wait(&full_cond,&mutex);}int product=rand()%100;buffer.push(product);cout<<"Producer produced:"<<product<<endl;pthread_cond_signal(&empty_cond);pthread_mutex_unlock(&mutex);usleep(100000);}}void*consumer(void*arg){while(true){pthread_mutex_lock(&mutex);while(buffer.empty()){pthread_cond_wait(&empty_cond,&mutex);}int product=buffer.front();buffer.pop();cout<<"Consumer consumed:"<<product<<endl;pthread_cond_signal(&full_cond);pthread_mutex_unlock(&mutex);usleep(200000);}}int main(){pthread_t producer_thread,consumer_thread;pthread_mutex_init(&mutex,NULL);pthread_cond_init(&full_cond,NULL);pthread_cond_init(&empty_cond,NULL);pthread_create(&producer_thread,NULL,producer, NULL);pthread_create(&consumer_thread,NULL,consumer, NULL);pthread_join(producer_thread,NULL);pthread_join(consumer_thread,NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&full_cond);pthread_cond_destroy(&empty_cond);return0;}```在这个例子中,我们使用了一个全局的`buffer`队列作为缓冲区,使用`pthread_mutex_t`类型的变量`mutex`来保护对缓冲区的访问,使用`pthread_cond_t`类型的变量`full_cond`和`empty_cond`来实现线程间的通信。