关于进程互斥-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退出临界区*/
}

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

相关推荐
Thexhy3231 天前
Linux学习,CentOS虚拟机网络存在问题,主网络接口 ens33没有分配到 IP 地址,按照这个流程,99% 的虚拟机无网络访问问题都能得到解决。请从第一
操作系统
CYRUS_STUDIO2 天前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
YxVoyager3 天前
操作系统(二) :CPU调度
操作系统
pusue_the_sun4 天前
简单概述操作系统的发展
操作系统·计算机组成原理
apolloyhl6 天前
深入理解 Linux 内核进程管理
linux·运维·服务器·操作系统
hour_go8 天前
用户态与内核态的深度解析:安全、效率与优化之道
笔记·操作系统
LUCIAZZZ9 天前
HTTPS优化简单总结
网络·网络协议·计算机网络·http·https·操作系统
fakerth11 天前
【OpenHarmony文件管理子系统】文件访问接口解析
操作系统·openharmony
Layflok11 天前
第三章 内存管理
笔记·操作系统·内存管理·王道笔记
fakerth13 天前
【OpenHarmony文件管理子系统】文件访问接口mod_fileio解析
操作系统·openharmony