最近學校開設了操作系統原理課程,老師要求用任意語言去模擬進程的同步和互斥問題。
在嘗試的寫了之后,發現這個問題非常有意思,故想記錄在博客中,作為自己的學習軌跡。
個人還是比較喜歡用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(); }
測試結果