java 与操作系统进程同步问题(一)————互斥问题
最近学校开设了操作系统原理课程,老师要求用任意语言去模拟进程的同步和互斥问题。
在尝试的写了之后,发现这个问题非常有意思,故想记录在博客中,作为自己的学习轨迹。
个人还是比较喜欢用Java语言,所以采用了java来编写。今天记录的是多个进程访问互斥资源量的问题,互斥即是某一资源同一时刻,只允许一个进程访问,在离散数学中,对互斥定义如下
事件A和B的交集为空,A与B就是互斥事件,也叫互不相容事件。也可叙述为:不可能同时发生的事件。如A∩B为不可能事件(A∩B=Φ),那么称事件A与事件B互斥,其含义是:事件A与事件B在任何一次试验中不会同时发生(百度百科)。
如日常生活中的打印机,就是一个公共资源,同一时刻,只允许一个任务进行,其他任务排队等待。
采用记录型信号量来实现。
相应的wait(Semaphore s) (wait操作就是p操作,我们的课本里是这种叫法)的伪代码就是
1 wait(Semaphore *s){ 2 s->value--; //value是资源个数 3 if(s->value < 0){ 4 block(s->list); //list是PCB(process_control_block)块 5 } 6 }
对应的signal(signal就是v操作)的伪代码就是:
signal(Semaphore *s){ s->value++; if(s->value >= 0) wakeup(s->list); }
所以首先我们得实现一个信号量类,采用synchronized块来模拟wait和signal操作 ,具体synchronized的细节请自行百度或者查阅其他博客园的文章,我理解的也不是特别透彻。
public class Semaphore { public Object lock = new Object(); //synchronized锁住的是对象 public int value; //资源个数 public Semaphore(int value) { this.value = value; } }
在该类中我们实现wait和signal方法
public static void Wait(Semaphore semaphore,String className) { //classname用来判断是那个线程 synchronized (semaphore.lock) { semaphore.value--; if (semaphore.value < 0) { try { System.out.println(className + "被阻塞"); semaphore.lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void Signal(Semaphore semaphore,String className){ synchronized (semaphore.lock) { semaphore.value++; if (semaphore.value <= 0) { System.out.println(className + "资源量足够,唤醒一个"); semaphore.lock.notify(); } } }
可以看到跟最开始的伪代码基本思想都是一样的。
到此,我们就已经完成了记录型信号量。
下面我们就用记录型信号量来完成互斥关系
首先给出用记录型信号量完成互斥关系的伪代码
operation() { while(1){ wait(mutex); //进入临界区 signal(mutex); //剩余区 } }
临界区:就是进程中访问临界资源的代码
我们模拟多个人使用打印机来模拟进程互斥问题。
一般解决同步问题要先确定信号量,互斥信号量非常好确定,就是打印机,我们可以设初始打印机资源为1
首先完成一个Runnable的子类,它就是对打印机进行的操作,即为上述的operation
public class PrinterUser implements Runnable{ //打印机信号量 Semaphore printer;
//确认线程身份 String userName; public PrinterUser(Semaphore printer,String userName) { // TODO 自动生成的构造函数存根 this.printer = printer; this.userName = userName; } @Override public void run() { // TODO 自动生成的方法存根 while(true){ Semaphore.Wait(printer, userName); System.out.println("正在打印"); Semaphore.Signal(printer, userName); System.out.println(userName+"打印完成"); } } }
给出测试
public static void main(String[] args) { Semaphore printer = new Semaphore(1); // TODO Auto-generated method stub Thread threada= new Thread(new PrinterUser(printer, "打印者1")); Thread threadb= new Thread(new PrinterUser(printer, "打印者2")); threada.start();threadb.start(); }
测试结果