进程同步小结

操作系统引入进程提高了资源利用率和系统吞吐量,但由于进程的异步性导致了系统混乱,尤其争用临界资源时,(例如:当多个进程去争用一台打印机时,有可能使多个进程的输出结果交织在一起难于区分)。为此,OS必须引入某种机制,即进程的同步机制(进程同步)。

4.1进程同步的基本概念

进程同步是指对多个相关进程在执行次序上进行协调,使系统中进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。用来实现同步的机制被称作同步机制。

4.1.1两种制约关系

所有进程都是相互独立的、进程以异步方式并发执行,致使进程在活动中会相互制约,制约关系可分两种。

直接:相互制约关系源于进程合作,表现为:进程---进程(同步)

间接:相互制约关系源于资源共享,表现为:进程---资源---进程(互斥)

1)同步

同步是进程间共同完成一项任务时直接发生相互作用的关系

同步举例:输入进程和计算进程通过单缓冲区来协调工作

同步进程之间具有合作关系

在执行时间上必须按一定的顺序协调进行

2)互斥

互斥是并发执行的多个进程由于竞争同一资源而产生的相互排斥的关系

互斥进程彼此在逻辑上是完全无关的

它们的运行不具有时间次序的特征

4.1.2临界资源

一次仅允许一个进程使用的共享资源,如果多个进程同时使用这些资源,则有可能造成系统的混乱,如:打印机,多个进程同时使用一台打印机,将使其输出结果交织在一起,难于区分;又如文件,多个进程同时写入同一个文件,内容也会混乱。

4.1.3临界区

如何保证诸进程互斥地访问临界资源?

每个进程中访问临界资源的那段代码叫临界区。

进入区:对要访问的临界资源进行检查,若未被访问,设正在访问标志。

退出区:将正在访问的标志恢复为未被访问的标志。

剩余区:其余部分。

while(TRUE)

{

进入区

临界区

退出区

     

剩余区

}

为了使多个进程能有效地共享临界资源,并使程序的执行具有可再现性,系统必须保证它们互斥地使用临界资源,即保证它们互斥地进入自己的临界区。如果一进程已进入临界区使用临界资源,另一企图进入临界区使用同一临界资源的进程便必须等待,直到前一进程退出临界区为止。不难看出,互斥的实质就是同步,互斥是同步的一种特殊形式。

对临界区进行管理时,可将标识临界区状态的变量看作一把锁,锁开就允许进入,否则等待。

4.1.4同步机制应遵循的规则

为实现进程互斥地进入自己的临界区,采用同步机制来协调各进程间地运行。

空闲让进——临界资源空闲时,应允许一个请求进入临界区的进程立即进入自己的临界区,以便有效地利用资源。

忙则等待——当临界资源正被访问时,其他要求进入临界区的进程必须等待,以保证对临界资源的互斥使用。

有限等待——任何要求访问临界资源的进程应能在有限的时间内进入自己的临界区,以免“死等”。

让权等待——不能进入临界区的进程应立即释放CPU,以免“忙等”。

4.2 硬件同步机制

(1)关中断

进程在临界区执行期间,计算机系统不响应中断,不会引发调度,也不会发生进程或者线程的切换。

但缺点很多,影响系统效率,不适用于多CPU系统等。

(2)利用Test-And-Set指令实现互斥

借助测试并设置这条硬件指令实现互斥,许多计算机提供了这种指令。一般性描述如下:

boolean Test-And-Set(boolean *lock)

{

  bool old;

old = *lock;

*lock = true;

return old;

}

这个指令可以看作一个函数进程,但是执行过程是不可分割的,原子操作,是一条原语。

while(TestAndSet(&lock));

critical section;

lock = false;

remainder section;

(3)Swap指令

这条指令也是原子指令,不会被中断,功能是交换两个字的内容。

为每个临界资源设置一个共享变量lock,true表示被占用,初值为false。每个进程中再设置一个局部变量key,用于和lock交换信息。

void Swap(bool *a, bool *b)

{

      bool tmp = *a;

      *a = *b;

      *b = tmp;

}

使用方法:

key = true;

while(key != false){

      Swap(&lock, &key);

}

critical section;

lock = false;

remainder section;

硬件方法的优点:适用于任意数目的进程,单处理机或多处理机。

硬件方法的缺点:可能导致饥饿现象。

4.3 信号量机制

为了实现同步,OS引入多种管理机制,其中信号量机制是最有效的。1965年荷兰的计算机科学家Dijkstra提出的进程同步方法。

信号量代表可用资源实体的数量。信号量又叫信号灯( semaphore ),是表示资源的实体,是一个与队列有关的整型变量,除初值外其值仅能由P、V原语操作来改变。操作系统利用信号量对进程和资源进行控制和管理。

公用(互斥)信号量:用于实现进程之间的互斥,初值为1,它所联系的一组并发进程均可对其实施P、V操作;

除初值外,信号量的值仅由P、V操作改变

P、V分别代表荷兰语的“等待”Wait,“发信号”Signal

P、V操作原语

—P操作(wait)原语 申请一个单位资源

—V操作(signal)原语 释放一个单位资源

注意:信号量不是在程序中定义变量获得的,程序里普通的全局变量、局部变量是不能当信号量的。

信号量由操作系统的内核分配,就算创建它的进程结束了,如果没有主动释放该内核对象,那么内核对象还会一直存在。正是利用两个进程同时访问同一个内核对象的特点实现的进程同步,不同的操作系统有不同的创建与访问内核对象的方法。

4.3.1  整型信号量

整型量,除初始化外,仅能通过两个原子操作来访问。

Wait、Signal操作是原子操作,不可中断。

整型信号量的主要问题是,只要S<=0 ,wait操作就会不断地测试,因而,没能做到“让权等待”,忙等。

4.3.2  记录型信号量

整型信号量未遵循“让权等待”原则,导致“忙等”。

记录型信号量:一般是由两个成员组成的数据结构,其中一个成员是整型变量,表示该信号量的值,另一个是指向PCB的指针。整型变量value代表资源数目、进程链表list代表所有等待进程。

记录型数据结构:

信号量的值是与相应资源的使用情况有关的。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,则其绝对值表示等待使用该资源的进程数,即在该信号量队列上排队的PCB的个数。

wait(semaphore *S)

{

  S->value--;

  if(S->value<0){block(S->list);}

}

signal(semaphore *S)

{

  S->value++;

  if(S->value<=0){wakeup(S->list);}

}

4.3.3 AND型信号量

前面介绍的进程互斥问题,属于多个进程共享一个临界资源。而AND型信号量是为了解决多个进程共享多个临界资源。

AND同步机制的基本思想:将进程在整个运行过程中需要的所有资源,一次性全部分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其他所有可能为之分配的资源,也不分配给它,即对临界资源的分配采取原子操作。

4.4.4信号量集

“信号量集”是指同时需要多种资源、每种占用的数目不同、且可分配的资源还存在一个临界值时的信号量处理。由于—次需要n个某类临界资源,因此如果通过n次wait操作申请这n个临界资源,操作效率很低,并可能出现死锁。

信号量集的基本思路就是在AND型信号量集的基础上进行扩充,在一次原语操作中完成所有的资源申请。

进程对信号量Si的测试值不再是1,而是该资源的分配下限ti,要求Si>ti,否则不予分配,进程对该资源的需求值为di,表示资源的占用量,进行Si=Si-di操作。

一般信号量集的几种特殊情况:

Swait(S, d, d),只有一个信号量S,允许每次申请d个资源,若现有资源数少于d,不予分配。

Swait(S, 1, 1),蜕化为一般的记录型信号量(S>1时)或互斥信号量(S=1时)。

Swait(S, 1, 0),当S>=1时,允许多个进程进入某特定区,当S变为0后,阻止任何进程进入特定区,相当于可控开关。

4.5 Windows下C++实现进程间同步

需包含头文件windows.h

常用操作mutex的函数有:CreateMutex / ReleaseMutex / OpenMutex / WaitForSingleObject / WaitForMultipleObjects。

CreateMutex函数,是找出当前系统是否已经存在指定进程的实例。如果没有则创建一个互斥体。

OpenMutex函数为现有的一个已命名互斥体对象创建一个新句柄。

一旦不再需要,注意一定要用 CloseHandle 关闭互斥体句柄。如对象的所有句柄都已关闭,那么对象也会删除。

进程A部分代码:

{

  HANDLE hMutex = CreateMutex(NULL, true, L”mutexTest”);

  WaitForSingleObject(hMutex, INFINITE);

  std::out<<”hello world”<<std::endl;

  int a = 0;

  while(std::cin>>a)

{

  if(a==1)

  {

    ReleaseMutex(hMutex);

      CloseHandle(hMutex);

    break;

}

}

}

进程B部分代码:

也是通过CreateMutex来创建同名互斥量,返回的是该互斥量在进程B中的一个新的指向。

int main(int argc, char** argv)

{

    HANDLE hMutex = CreateMutex(NULL, true, L”mutexTest”);

    DWORD error = GetLastError(); //应进行判断,这里先忽略

    WaitForSingleObject(hMutex, INFINITE);

     std::out<<”good bye!”<<std::endl;

   ReleaseMutex(hMutex);

     CloseHandle(hMutex);

}

4.6 经典的进程同步问题

生产者消费者问题、读者写者问题、哲学家进餐问题,孙老师的视频里讲的很清楚了,这里不准备展开讲了,如果有不懂的地方,请在学习通里发起讨论话题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值