进程对临界资源的互斥访问

临界资源与临界区

临界资源(critical resource):一次只能供一个进程使用的资源。   如:硬件有打印机等,软件有变量,磁盘文件(写入的时候)。

临界区(critical section):把进程中访问临界资源的那段代码成为临界区。

为了实现临界资源的互斥访问,只要做到进程互斥地进去自己的临界区,便可以实现进程对临界资源的互斥访问。

同步机制

为实现各进程互质地访问自己的临界区,操作系统需要同步机制来协调各进程的运行。

1、同步机制的规则

  (1)空闲让进:当无进程处于临界区,表明临界资源处于空闲状态,允许请求进去临界区的进程进去临界区

  (2)忙则等待:当有进程处于临界区,表明临界资源正在访问,其他请求进入临界区的进程必须等待。

  (3)有限等待:应使在等待的进程在有限的事件内进入自己的临界区,避免"死等"状态

  (4)让权等待:当进程不能进入自己的临界区,应立即释放处理机,以避免进入"忙等"状态

2、硬件同步机制

 为临界资源设置一把锁,当临界资源无进程使用时,锁是打开的,当临界资源正在被进程使用时,则锁是关闭的。

锁可能是一个布尔变量lock,初始时,lock = FALSE,那么每次访问临界资源时,都要进程锁测试。

bool lock = false;
    if(!lock)
    {
        lock = true;
        access critical section;//访问临界区资源
    }

但是在多任务的处理机中,可能会发生错误。假设有2个进程都要访问同一临界资源,进程a通过了锁测试,但是未将lock设为true时,发生了进程调度,进程b开始执行锁测试,同样通过了锁测试,从而使得两个进程访问同一个临界资源。

  (1)关中断:在进入锁测试之前关闭中断,直到完成锁测试并且上锁之后才打开中断,但是这样很不好,限制了CPU处理任务的能力,而且也很危险,如果用户在中断后写个死循环,那不就死机了。

  (2)利用Test-and-set指令:这是一条硬件指令,且该指令是原子操作(atomic operataion),原子操作指的是该执行过程要么不做,那么全做,即像原子一样不可分割。下面的TS就是一个原子操作,所以不会发生上面所说的问题。

bool TS(bool *lock)//lock 为临界资源的锁
{
    bool old ;
    old = lock;
    lock = true;//如果锁为true,那么这句不影响锁,如果锁为false,那么正好上锁
    return old;
}
while(TS(&lock));//循环测试直到TS(&lock) 为false
access critical section;
lock = false;

  (3)利用Swap指令:该指令也是硬件指令,且是原子操作。可以看出下面的代码其实思想是和上面的代码思想是一样的。只不过实现方式不同而已。

void swap(bool *a, bool *b)
{
    //如果a==true,那么swap语句不影响锁,如果a==false,那么正好上锁
    bool tmp
    tmp = *a;
    *a = *b;
    *b = tmp;
}
bool key = true;
do{
    swap(&lock,&key);
}while(key!=false)

 

3、信号量机制

  (1)整形信号量:用一个整型的信号量S来表示资源的个数,然后通过两个原子操作来进行判断,这两个原子操作是wait(S)和singal(S),也叫做P和V

其实这些操作很容易想出来,但是你不能自己直接写if-else来判断,因为你的这些代码可能不具备原子性,所以会发生错误。

wait(S)
{
    while(S<=0);
    S--;
}
singal(S)
{
    S++;
}


//使用wait(S)和singal(S)来做到互斥访问
wait(S);
access critical section;
singal(S);

  (2)记录型信号量:在整形信号量中,只要S<0,那么wait原子操作就会不停地进行测试,直到S>=0,这种不断测试,知道满足条件的情况叫做忙等待。这样不如使得该进程进入阻塞状态,等满足条件时再唤醒该进程。而且这样更有利于提高CPU的效率。 这就是记录型信号量所做的事情。

wait原语所做的操作是将S->value--,如果减完后小于0,那么说明临界资源不够,因此调用block原语,将当前进程阻塞,并记录到链表S->list中

singal原语所做的操作是将S->value++,如果加完后小于等于0,那么说明链表中S->list有阻塞的进程,因此调用wakeup原语唤醒该进程来获得临界资源。

//记录型数据结构
typedef struct
{
    int value;
    struct process_control_block *list;
}semaphore;


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

singal(semaphore *S)
{
    S->value++;
    if(S->value<=0) wakeup(S->list);
}

 

其实硬件指令同步和软件同步所做的操作都是一样的,只是他们实现的方式不同而已,一个是硬件,一个是软件。

转载于:https://www.cnblogs.com/beMaster/p/4986825.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值