操作系统(7)进程间通信

来源:互联网 发布:经度纬度查询软件 编辑:程序博客网 时间:2024/06/05 15:19

1、信号量解决读者-写者问题:有两组并发进程:读者和写者,共享文件F,要求:

1)允许多个读者同时对文件执行读操作。

2)只允许一个写者对文件执行写操作。

3)任何写者在完成写操作之前不允许其他读者或写者工作。

4)写者在执行写操作之前,应让已有的写者和读者全部退出。

单纯引入信号量不能解决此问题,必须引入计数器readcount对读进程计数,mutex是用于对计数器readcount操作的互斥信号量,writeblock表示是否允许写的信号量。

int readcount = 0;          //读进程计数

semaphore writeblock, mutex;

writeblock = 1;  mutex = 1;

cobegin 

process reader_i( )   {                    process writer_j( )   { 

      P(mutex);                                         P(writeblock);

      readcount++;                                   {写文件};

       if(readcount ==1)                            V(writeblock);

             P(writeblock);                     }

             V(mutex);

             {读文件};

             P(mutex);

             readcount --;

             if(readcount == 0)

                 V(writeblock);

             V(mutex);

}

coend

2、信号量解决理发师问题:

引入3个信号量和一个控制变量:控制变量waiting记录等候理发的顾客坐的椅子数,初值为0;信号量customers记录等候理发的顾客数,并用于阻塞理发师进程,其初值为0;信号量barbers记录正在等候理发的顾客数,并用于阻塞顾客进程,其初值为0;信号量mutex用于互斥,其初值为1;

int waiting = 0;             //等待理发的顾客坐的椅子数

int CHAIRS = N;              //为顾客准备的椅子数

semaphore customers, barbers, mutex;

customers = 0;  barbers = 0; mutex = 1;

cobegin

process barber( )  {

        while( true)  {

            P(customers);             //判断是否有顾客,若无顾客,理发师睡眠

            P(mutex);                   //若有顾客,进入临界区

            waiting --;                   //等候顾客数减1

            V(barbers);               //理发师准备为顾客理发

            V(mutex);                  //退出临界区

            cut_hair( );                //理发师正在理发(非临界区)

       }

}

process customer_i( )  {

         P(mutex);                        //进入临界区

         if(waiting<CHAIRS)  {               //判断是否有空椅子

                waiting ++;                     //等候顾客数加1

                 V(customers);                  //唤醒理发师

                 V(mutex);                    //退出临界区

                  P(barbers);               //理发师忙,顾客坐着等待

                   get_haircut( );           //否则,顾客可以理发

           }

           else

                   V(mutex);              //人满了,顾客离开

}

coend

3、管程:属性有共享性,安全性,互斥性。

基本思路:把分散在各进程中的临界区集中起来管理,并把共享资源用数据结构抽象表示出来,由于临界区是访问共享资源的代码段,建立一个“秘书”程序管理到来的访问,“秘书”每次只让一个进程来访。

1)条件变量:一种数据结构,只有在管程中才能被访问,对管程是全局的,只能通过两个原语操作来控制它。

2)wait( ):挂起调用进程并释放管程,直至另一个进程在条件变量上执行signal( )。

3)如果有其他进程因对条件变量执行wait( )而被挂起,便释放之。如果没有进程在等待,那么,信号不被保存。

注意:wait操作一般应在signal操作之前发出。

4、进程的通信方式:

1)信号:

是一种软中断,只能发送单个信号而不能传送数据。信号处理完毕后,被中断进程将恢复执行。用户、内核和进程都能生成信号请求。由进程执行指令而产生的信号称为同步信号。像击键之类的进程以外的事件所引起的信号称为异步信号。信号有一个产生、传送、捕获和释放的过程。

2)管道:

实质是一个共享文件,即利用辅助存储器来进行数据通信。管道是单向的,发送进程视管道文件为输出文件,以字符流的形式把大量数据送入管道;接收进程视管道文件为输入文件,从管道中接收数据。

3)共享主存:

指在主存中开辟一个公用存储区,要通信的进程把自己的虚拟地址空间映射到共享主存区。共享主存的页面在每个共享进程的页表中都有页表项引用,但无须在所有进程的虚存段都有相同的地址。因为不止一个进程可将共享主存映射到自己的虚地址空间中去,读写共享主存区的代码段通常被认为是临界区。

4)消息传递

交互式并发进程通过信号量及PV操作可实现进程的互斥和同步。消息传递的复杂性在于:地址空间的隔离,发送进程无法将消息直接复制到接收进程的地址空间中,这项工作只能由操作系统来完成。提供两条原语send和receive,前者向一个给定的目标进程发送一条消息,后者从一个给定的源进程接收一条消息。为了实现异步通信,必须采用间接的通信方式,进程之间发送或接收消息通过一个共享的数据结构——信箱进行,消息可被理解成信件,每个信箱都有唯一标识符。

//消息传递机制解决进程互斥问题

create_mailbox(box);

send( box, null);

void Pi( )  {    //i=1,2,...n

        message msg;

        while(true)  {

              receive( box, msg);

              {临界区};

              send(box, msg);

          }

}

cobegin

    Pi( );

coend

5、进程使用独占型资源必须按照以下次序进行:申请资源、使用资源、归还资源。

死锁:

两个进程分别等待对方所占用的一个资源,于是两者都不能执行而处于永远等待状态。产生死锁原因很多,例如:进程推进顺序不当,PV操作使用不妥,同类资源分配不均或对某些资源的使用未加限制。

解决方法:死锁防止,死锁避免,死锁检测和恢复。

产生死锁必定同时保持4个必要条件:

1)互斥条件:系统中存在临界资源,进程应互斥地使用这些资源。

2)占有和等待条件:进程在请求资源得不到满足而等待时,不释放已占有的资源。

3)不剥夺条件:已被占用的资源只能由属主释放,不允许被其他进程剥夺。

4)循环等待条件:存在循环等待链,其中,每个进程都在链中等待下一个进程所持有的资源,造成这组进程处于永远等待状态。

6、银行家算法:

系统中的所有进程放入进程集合,在安全状态下系统收到进程的资源请求后,先把资源试探性地分配给它。现在,系统将剩下的可用资源和进程集合中其他进程还需要的资源数进行比较,找出剩余资源能满足最大需求量的进程,从而保证进程运行完毕后并归还全部资源。这时,把这个进程从进程集合中删除,归还其所占用的所有资源,系统的剩余资源更多,反复执行上述步骤。最后,检查进程集合,若为空则表明本次申请可行,系统处于安全状态,可以真正实施本次分配;否则,只要进程集合非空,系统便处于不安全状态,本次资源分配暂不实施,让申请资源的进程等待。

7、资源分配图和死锁定理:

系统定时地运行“死锁检测程序”,判断系统内是否已经出现死锁,如果检测到系统已死锁,在采取措施解除它。实现的难点在于,要确定何时运行死锁检测算法。

注意,在进程-资源分配图中存在环路并不一定必发生死锁,因为循环等待资源仅是死锁发生的必要条件,而不是充分条件。

常用的解除系统死锁方法:

资源剥夺法。进程回退法。进程撤销法。系统重启法。

8、互斥对象用于控制共享资源的互斥访问,在一个时刻,互斥对象只能被一个线程使用,其相关API包括:

1)CreateMutex:创建一个互斥对象,返回对象句柄。

2)OpenMutex:打开并返回一个已存在的互斥对象句柄。

3)ReleaseMutex:释放对互斥对象的占用,使之可用。

9、信号量对象就是资源信号量,其初始值范围在0到指定的最大值之间,用于限制并发访问的线程数,其相关API为:

1)CreateSemaphore:创建一个信号量对象,在输入参数中指定初始值和最大值,返回对象句柄。

2)OpenSemaphore:打开并返回一个已存在的信号量对象句柄。

3)ReleaseSemaphore:释放对信号量对象的占用,使之可用。

10、事件对象相当于触发器,可用于通知一个或多个线程某事件已出现,相关API:

1)CreateEvent:创建一个事件对象,返回对象句柄。

2)OpenEvent:打开并返回一个已存在的事件对象句柄。

3)SetEvent和PulseEvent:设置所指定的事件对象为可用状态。

4)ResetEvent:设置所指定的事件对象为不可用状态。

注意:对于以上三种同步对象,等待操作WaitForSingleObject和WaitForMultipleObject,前者可在指定的时间内等待指定对象转换为可用状态;后者可在指定的时间内等待多个对象转换为可用状态。


0 0