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

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
请按任意键继续. . .

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

#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");
}

但此时程序的输出:

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++实现
#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的实现
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_regionint 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;}}

此时打印的数字为:

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 算法的源码为:

#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退出临界区*/
}

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

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

  1. 操作系统之进程管理:8、进程互斥的软件实现方法(单标志、双标志、Peterson)

    8.进程互斥的软件实现方法 思维导图 引言 1.单标志法 2.双标志法 双标志先 双标志后检查法 3.Peterson算法 思维导图 引言 上图中,进程AB同时访问打印机资源,这样就可能将AB的打印内 ...

  2. Peterson‘s Algorithm皮特森算法详解

    Peterson算法是实现进程互斥访问临界区的一种方法,避免了单标志法必须交替访问的限制,以及双标志法后检验的"饥饿"问题. Peterson算法实现如下: //操作系统 临界区互 ...

  3. peterson算法p0流程图_Peterson's Algorism皮特森算法详解

    Peterson算法是实现进程互斥访问临界区的一种方法,避免了单标志法必须交替访问的限制,以及双标志法后检验的"饥饿"问题. Peterson算法实现如下: Pi进程: flag[ ...

  4. Peterson‘s Algorism皮特森算法详解

    本文将flag比作进入临界区的意向,turn比作访问请求.对于线程0,turn=j表达了访问请求. flag[i] = TRUE将自身的访问位置为1,turn = j 向对方发出访问请求: 对于线程0 ...

  5. 进程互斥软件算法(Lamport面包店算法和Eisenberg算法)

    实现进程互斥的软件的结构框架是: Framework Repeat entry section critical section exit section remainder section Unti ...

  6. 卡住无法查看到所有进程_进程同步 进程互斥 软件和硬件实现方式 信号量机制 信号量机制实现进程同步,进程互斥,前驱关系...

    参考:https://www.bilibili.com/video/av31584226/?p=9 进程具有异步性的特征,异步性是指,各并发执行的进程以各自独立的,不可预知的速度向前推进. 回忆我们之 ...

  7. 操作系统-进程同步和进程互斥

    操作系统-王道老师 第二章02-进程同步和进程互斥 目录: 1.进程同步.进程互斥     1.1 进程同步     1.2 进程互斥 2.进程互斥的软件实现方法     2.1 单标志法     2 ...

  8. 十三、进程互斥的软件实现方法

    一.知识总览 二.单标志法 **1.算法思想:**两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程,也就是说每个进程进入临界区的权限只能被另一个进程赋予. **单标志法所存在的问题:**只 ...

  9. [OS复习]进程互斥与同步2

    互斥与同步的解决策略 当前,利用软件方法.硬件方法.信号量方法.管程方法.消息传递方法都可以有效地解决进程间的互斥与同步,其中信号量的方法更具有优势(目前已经通用). 1. 软件方法: 软件方法是指由 ...

最新文章

  1. 【数论基础】欧几里德算法及其各种应用
  2. Android Launcher3(一) -- 启动过程
  3. mysql设置表名字为占位符_这可能是把MySQL存储引擎讲解的最清楚的一篇文章了
  4. android 动态设置View的高度和宽度,ViewTreeObserver使用
  5. C++设计模式-状态模式
  6. 2-自定义 Mybatis 框架
  7. android app攻击与防范论文,基于Android平台的应用程序安全保护研究与应用
  8. [文摘]Eclipse中如何批量替换
  9. win11桌面图标模糊怎么办 windows11桌面图标模糊的解决方法
  10. Linux中cinder的作用,11-cinder块存储服务部署
  11. 泛微云桥e-birdge之金蝶云之家集成配置手册
  12. DH(Diffie-Hellman)算法本元根(原根)求法
  13. sqoop导数到各个数据库,可以套用
  14. 湖南大学计算机学院陈浩,杨圣洪-湖大信息科学与工程学院
  15. 计算机科学 投稿 邮箱,《计算机时代》期刊投稿【编辑部_邮箱_地址_怎么样_版面费_代发表】...
  16. getTime()方法在苹果系统的bug
  17. ImageMagick windows下的安装和gif动图制作
  18. 智者将建立桥梁,而愚者则建立高墙。 ----《黑豹》
  19. Kubernetes Dashboard的安装与配置
  20. php phonegap,phonegap操作数据库详解

热门文章

  1. mancation 男性假期生活英语English
  2. mysql 5.7 登录时报:ERROR 1862 (HY000): Your password has expired
  3. com.example.web.DemoServlet不是Servlet
  4. 【8-13】手势传感器PAJ7620U2测试 实现手势控制无人机
  5. android:在照片上绘制涂鸦
  6. mysql 谓词_Mysql谓词下推技术
  7. 13 年 Java 老兵的微服务战地笔记 | 文末有1元福利
  8. 树莓派——opencv打开树莓派摄像头调试记录
  9. ajax异步修改新闻状态,ajax同步刷新
  10. Vijos1901 学姐的钱包