关于进程互斥-Peterson(皮特森)算法的讨论

首先我们用c++实现一个功能 两个线程通过for循环输出0 1 2 3 4 5 6 7 8 9 用c++并发执行来实现。

我们希望程序的输出为:

erlang 复制代码
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
请按任意键继续. . .

那么代码可能会是这样的:

C++ 复制代码
#include<thread>
#include<iostream>
using namespace std;
void enter_region() {
	for (int s = 0; s < 10; s++) cout << s << " "; //输出函数
	cout << endl;	//打印回车
}
int main()
{//并发执行f1与f2线程
	for (int i = 0; i < 3; i++)
	{
		thread f1(enter_region);
		thread f2(enter_region);
		f1.join();//等待f1线程结束
		f2.join();//等待f2线程结束
	}
	system("pause");
}

但此时程序的输出:

erlang 复制代码
00 1 12 2 3 34 54 56 67 78 89 90 01 2 3 4 5 61 72 83 94  
5 6 7 8 9  
0 01 12 23 34 4 55 66 77 88 99  
请按任意键继续. . .

这不是我们想要的程序输出

所以我们需要通过一种方法来限制不让两个线程随意的打印输出到屏幕

下面介绍一种算法来限制两个线程:

C++ 复制代码
//c++实现
#include<thread>
#include<iostream>
using namespace std;
atomic<int> tun;				//线程安全标志位,模拟原子操作
bool i[2] = { false };//初始化
void leave_region(int process)			//退出屏幕打印函数
{
	i[process] = false;
}
void enter_region(int process)				//输出函数
{
	i[process] = true;		//当前进程准备进行屏幕打印
	tun = process;             //将tun设置为要进入屏幕打印的进程
	int other = 1 - process;   //获取另外一个线程
	while (tun == process && i[other] == true);	//循环等待屏幕打印(临界区)空闲
	for (int s = 0; s < 10; s++) cout << s << " "; //输出函数
	cout << endl;	//打印空格
	leave_region(process);  //退出打印屏幕
}
int main()
{//并发执行两个线程
	for (int i = 0; i < 3; i++)l
	{
		thread f1(enter_region,1);
		thread f2(enter_region,0);
		f1.join();//等待f1线程结束
		f2.join();//等待f2线程结束
	}
	system("pause");
}
java 复制代码
//java的实现
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;

public class fun {
    public static boolean completion[]={false,false}; //初始化
    //标志位.模拟原子操作
    public static AtomicInteger falg=new AtomicInteger();
    public static void main(String[] args) throws InterruptedException {
        for (int j=0;j<10;j++){
            Thread thread1=new Thread(()->enter_region(1));
            Thread thread2=new Thread(()->enter_region(0));
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
        }
    }

    public static void enter_region(int process){ //输出函数 enter_region
        int other=1-process;
        completion[process]=true; ////当前进程准备进行屏幕打印
        falg.set(process);
        while (falg.get()==process&& completion[other]==true);//循环等待进入屏幕打印
        for (int i = 0; i < 10; i++) System.out.print(i+" ");//输出函数
        System.out.println();
        leave_region(process);//退出屏幕打印
    }

    public static void leave_region(int process){
        completion[process]=false;
    }

}

此时打印的数字为:

erlang 复制代码
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
0 1 2 3 4 5 6 7 8 9  
请按任意键继续. . .

下面来讲解一下这个算法。现在线程1正在打印屏幕,如果他不调用退出函数,那么线程2里面的i[0]==true永远为真,所以线程2就会一直在循环(这种情况叫做忙等待),当调用了退出函数,那么线程2也就进行了打印。这种算法就是著名的 Peterson算法 。这么看代码可能不是很好懂,如果感兴趣,你可以尝试用vs实现以下这个代码。 后期增加了java的实现方法,可以自己复制跑一次,在这里打印的屏幕函数段称为临界区临界区段。

可能会有人觉得用互斥锁,或者警告变量的方法都可以实现。但是有一个问题需要我们考虑。

先拿锁变量(用一个布尔变量来代表临界区的锁)来说,如果在线程1在查看锁是打开的状态的时候,进程2也发现他是打开的状态,这样就会发生两个进程同时在打印的状态。

再来说说警告变量(用一个值来表示下一个要进入临界区的线程),如果一个线程1做完打印的程序,他就会把变量变成0,但此时线程0并不想进入打印屏幕,而线程1很快又要进入临界区,此时就会发生两个进程都在临界区外的状况。说明这不是 一个很好的方法。

1981年,G.L.peterson发现一种特别好的互斥方法,此方法就是 Peterson算法的。 Peterson 算法的源码为:

C 复制代码
#define FLASE 0
#define TRUE  1
#define N 2                           /*进程的数量*/
int turn;                             /*标志位*/
int interested[N]                     /*所有值初始化为0(FALSE)*/
void enter_region(int process)        /*进程是0或1*/
{
    int other;                       /*定义另一个进程号*/
    other=1-process;                 /*另一个进程*/
    interested[process]=TRUE;        /*表示当前进程需要进入临界区*/
    turn=process                     /*将turn设置为当前进程*/
    while(turn==process&&interested[other]==TRUE);
     /*other进程想要进入临界区,把turn变为other,因为process进程为true便陷入循环(忙等待)但只有当porcess进程调用leave_region退出临界区,此时other进程的enter_region函数while循环interested[other]==TRUE成立才会使other进程退出循环进入临界区*/
}
void leave_region(int process)       /*进程推出临界区调用函数*/
{
    interested(process)=FALSE;       /*进程process退出临界区*/
}

参考书籍:现代操作系统(原书第四版)

相关推荐
彩妙不是菜喵8 小时前
操作系统中的Linux:进程详解--->(深入浅出)从入门到精通
linux·操作系统
农民真快落9 小时前
【操作系统】手撸xv6操作系统——types.h/param.h/memlayout.h/riscv.h/defs.h头文件解析
操作系统·risc-v·嵌入式软件·xv6
小当家.1051 天前
操作系统期末考试基础知识点速成:高频考点与题集精要
考研·操作系统·计算机基础·速成·大学·期末考试
seasonsyy1 天前
为虚拟机分配内存和磁盘容量
windows·操作系统·内存·vmware·磁盘空间
想用offer打牌1 天前
一站式讲清IO多路复用(轻松愉悦版)
后端·面试·操作系统
seasonsyy1 天前
在虚拟机中安装操作系统需要U盘吗?
windows·操作系统·vmware·虚拟机
fakerth1 天前
【OpenHarmony】升级服务组件(UpdateService)
操作系统·openharmony
fakerth1 天前
【OpenHarmony】Updater 升级包安装组件
操作系统·openharmony
AlexMercer10122 天前
【操作系统】操作系统期末考试 简答题 焚决
c语言·经验分享·笔记·操作系统
brave and determined3 天前
ESP32 FreeRTOS (day1)入门教程 (ESP-IDF版):从超级循环到多任务的系统化思维
操作系统·esp32·freertos·任务·任务调度器·任务控制块·嵌入式设计