IPC中避免竞争条件-严格轮换法

在IPC问题中,避免竞争条件实现互斥有多种方案:

  • 1.屏蔽中断
  • 2.锁变量
  • 3.严格轮换法
  • 4.Peterson解法
  • 5.TSL指令

避免竞争条件 :
1 -任何两个进程不能同时处于其临界区
2 -不应对CPU的速度与数量进行比较
3 -临界区外运行的进程不得阻塞其他进程
4 -不得使进程无限期等待进入临界区

本文中着重介绍严格轮换法:
所谓的严格轮换法就是引入一个变量turn指示当前轮到哪个进程进入临界区,比如目前有两个进程0和1,一开始,我们让turn为0,进程0检查turn是否为0,当前turn为0,所以进程0进入临界区,而进程1发现turn为0,所以在外等待,一直等待turn的值变为1,像这样连续测试一个变量直到某个值出现为止的过程称为忙等待,在进程0退出临界区后,将turn置为1,这时进程1进入临界区,进程0完成剩余的工作,如此循环。

下面利用代码来直观理解一下流程:
代码借鉴于:https://blog.csdn.net/qq_41636947/article/details/101105143

#include <windows.h>
#include <cstdio>
#include <iostream>
#include <process.h>

using namespace  std;

int turn;  //全局变量
CRITICAL_SECTION cs;  //临界区

// DWORD == double word 一般用来保存地址或者存放指针
// WINAPI  == _stdcall
// LPVOID == void* 没有类型的指针
DWORD WINAPI fun_1(LPVOID p){
    while(TRUE){
        while(turn!=0);
        EnterCriticalSection(&cs);  //进入临界区
        cout<<"process 0: ";
        turn = 1;               
        cout<<turn<<'\n';
        LeaveCriticalSection(&cs); //离开临界区
    }
}

DWORD WINAPI fun_2(LPVOID p){
    while(TRUE){
        while(turn!=1);
        EnterCriticalSection(&cs);  
        cout<<"process 1: ";
        turn = 0;
        cout<<turn<<'\n';
        LeaveCriticalSection(&cs);
    }
}
int main()
{
    InitializeCriticalSection(&cs);
    HANDLE th1,th2;  //创建两个进程
    th1 = CreateThread(nullptr,0,fun_1, nullptr,0, nullptr);
    th2 = CreateThread(nullptr,0,fun_2, nullptr,0, nullptr);
    Sleep(1000);    //让进程0和进程1有足够的反应时间
    CloseHandle(th1);
    CloseHandle(th2);
    return 0;
}

代码运行结果:


result

存在的问题

从结果来看,进程0和进程1的确在进入临界区时互斥,但这个方法还是存在一个竞争条件。
思考一下,当进程1退出临界区并将turn设置为0时,进程1进入非临界区工作,这时进程0检查到turn为0,所以进程0进入临界区,而且进程0很快离开临界区(这次非常快完成工作),然后将turn置为1,同样很快离开非临界区进入下一轮循环,但此时,进程1还在非临界区工作,而进程0就会被阻塞,而这种情况不满足避免竞争条件中的3:临界区外运行的进程不能阻塞其他进程,所以严格轮换法不是一种很好的解决方案。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。