临界资源是一次仅允许一个进程使用的共享资源。各进程采取互斥的方式,实现共享的资源称作临界资源。属于临界资源的硬件有,打印机,磁带机等;软件有消息队列,变量,数组,缓冲区等。诸进程间采取互斥方式,实现对这种资源的共享。 每个进程中访问临界资源的那段代码称为临界区,每次只允许一个进程进入临界区,进入后,不允许其他进程进入。不论是硬件临界资源还是软件临界资源,多个进程必须互斥的对它进行访问。多个进程涉及到同一个临界资源的的临界区称为相关临界区。使用临界区时,一般不允许其运行时间过长,只要运行在临界区的线程还没有离开,其他所有进入此临界区的线程都会被挂起而进入等待状态,并在一定程度上影响程序的运行性能。
临界区使用原则: (1) 空闲让进:无进程处于临界区时,若有进程要求进入临界区应立即允许进入。 (2) 忙则等待:当已有进程进入临界区时,其他试图进入各自临界区的进程必须等待,以保证诸进程互斥地进入临界区。 (3) 有限等待:有若干进程要求进入临界区时,应在有限时间内使一进程进入临界区,即它们不应相互等待而谁都不进入临界区。 (4) 让权等待:对于等待进入临界区的进程必须释放其占有地CPU。
含义:信号量相当于一个信号灯,表示状态,是在多线程环境下使用的一种设施,可以用来保证两个或多个关键代码段不被并发调用。 作用:用来解决进程同步于互斥问题的机制,包括一个称为信号量的变量和对它进行的两个原语操作。
假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽烟。抽烟者卷起并抽掉一颗烟需要有三种材料:烟草、纸和胶水。一个抽烟者有烟草,一个有纸,另一个有胶水。系统中还有两个供应者进程,它们无限地供应所有三种材料,但每次仅轮流提供三种材料中的两种。得到缺失的两种材料的抽烟者在卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。这一过程重复进行。 请用信号量机制编程,实现该问题要求的功能。
问题分析:该问题本质是“可生产多种产品的多生产者-多消费者问题”。三个抽烟者相当于三个不同的消费者,他们每次只会有一个抽烟者可以抽到烟,其余两个则需要等待。而在这里默认空间大小只有一个单元,即供应者每次放下两种材料后都会停下来等待直到有消费者使用了这两种材料,他才会继续放另两种材料。相当于说缓冲区的大小为1。
关系分析:供应者与三个抽烟者分别是同步关系。由于供应者无法同时满足两个或 以上的抽烟者,三个抽烟者对抽烟这个动作互斥。进程分析:这里有五个进程。两个供应者作为生产者向三个抽烟者提供材料。信号量设置:
信号量offer1、offer2、offer3分别表示烟草和纸组合的资源、烟草和胶水组合的资源、纸和胶水组合的资源。因为开始时没有资源,所以将唤醒消费者的三个信号的信号量初始值都设为0。随机数设置:生产者要能提供三种组合的原料:烟草,纸,烟草,胶水,或是纸和胶水,这就需要一个随机数,来决定提供哪种组合的原料。这里用random存储随机数。信号量finish用于互斥进行抽烟动作。finish初始值为0,表示无人抽烟。测试结果: 完整代码:
#include<iostream> #include<string> #include<algorithm> #include<Windows.h> #include<process.h> using namespace std; int random=0; HANDLE offer1,offer2,offer3; HANDLE finish; unsigned __stdcall threadProvider(void *) { while(1) { random=rand()%3; if(random == 0) ReleaseSemaphore(offer1,1,NULL); else if(random == 1) ReleaseSemaphore(offer2,1,NULL); else ReleaseSemaphore(offer3,1,NULL); WaitForSingleObject(finish,INFINITE); } return 1; } unsigned __stdcall threadSmoker1(void *) { while(1) { WaitForSingleObject(offer1,INFINITE); cout<<"Smoker 1 is smoking now."<<endl; Sleep(1000); ReleaseSemaphore(finish,1,NULL); } return 2; } unsigned __stdcall threadSmoker2(void *) { while(1) { WaitForSingleObject(offer2,INFINITE); cout<<"Smoker 2 is smoking now."<<endl; Sleep(1000); ReleaseSemaphore(finish,1,NULL); } return 3; } unsigned __stdcall threadSmoker3(void *) { while(1) { WaitForSingleObject(offer3,INFINITE); cout<<"Smoker 3 is smoking now."<<endl; Sleep(1000); ReleaseSemaphore(finish,1,NULL); } return 4; } void process_Smoker() { offer1=CreateSemaphore(NULL,0,1,NULL); offer2=CreateSemaphore(NULL,0,1,NULL); offer3=CreateSemaphore(NULL,0,1,NULL); finish=CreateSemaphore(NULL,0,1,NULL); HANDLE hth1,hth2,hth3,hth4; hth1=(HANDLE)_beginthreadex(NULL,0,threadProvider,NULL,0,NULL); hth2=(HANDLE)_beginthreadex(NULL,0,threadSmoker1,NULL,0,NULL); hth3=(HANDLE)_beginthreadex(NULL,0,threadSmoker2,NULL,0,NULL); hth4=(HANDLE)_beginthreadex(NULL,0,threadSmoker3,NULL,0,NULL); WaitForSingleObject(hth1,INFINITE); WaitForSingleObject(hth2,INFINITE); WaitForSingleObject(hth3,INFINITE); WaitForSingleObject(hth4,INFINITE); CloseHandle(hth1); CloseHandle(hth2); CloseHandle(hth3); CloseHandle(hth4); CloseHandle(offer1); CloseHandle(offer2); CloseHandle(offer3); CloseHandle(finish); } int main() { process_Smoker(); return 0; }