• Critical Section Problems


      Here I wish to show you some of my DIY demo programs demonstrating how Critical Section Problems can be solved by using Peterson's Algorithm, Spinlocks as well as Semaphores.

      This is a demo program of Peterson's Algorithm. Here two clients send messages to their corresponding server threads, and the two server threads print messages on the same terminal without interference.

      1 import java.util.concurrent.atomic.*;
      2 import java.util.*;
      3 import java.io.*;
      4 
      5 class Server {
      6     /**
      7      *  This class simulates a Server System that can
      8      *         service two Client Threads simultaneously
      9      */
     10     private class Task extends Thread {
     11         /**
     12          *  This class simulates a Server Thread
     13          */
     14         private int id, cnt;
     15         private Scanner in;
     16         
     17         public Task(int id,PipedOutputStream pout) throws IOException {
     18             this.id = id;
     19             in = new Scanner(new PipedInputStream(pout));
     20         }
     21         public void run() {
     22             /* Print the messages from the client */
     23             try {
     24                while (!getAndPrintMsg());
     25            } catch (Exception e) {
     26                 System.err.println("Error 2: "+e);
     27             }
     28         }
     29         private boolean getAndPrintMsg() throws IOException {
     30             /* 
     31              * Implementation of Peterson's Algorithm:
     32              */
     33             String str = in.nextLine();
     34             if (!str.equals("over")) {
     35                 flag[id].set(true);
     36                 turn.set(1-id);
     37                 while (flag[1-id].get()&&turn.get()==1-id);
     38                 System.out.println("	"+this+" #"+(++cnt)+": 	"+str);    // critical section
     39                 flag[id].set(false);
     40                 return false;
     41             } else {
     42                 return true;
     43             }
     44         }
     45         public String toString() {
     46             return "Server " + (id+1);
     47         }
     48     }
     49     
     50     private AtomicBoolean[] flag;
     51     private AtomicInteger turn;
     52     
     53     public Server(PipedOutputStream pout1,PipedOutputStream pout2) {
     54         // initialization of flag and turn
     55         flag = new AtomicBoolean[2];
     56         for (int i=0;i<2;i++) {
     57             flag[i] = new AtomicBoolean(false);
     58         }
     59         turn = new AtomicInteger(0);
     60         try {
     61             (new Task(0,pout1)).start();
     62             (new Task(1,pout2)).start();
     63         } catch (IOException e) {
     64             e.printStackTrace();
     65         }
     66     }
     67 }
     68 
     69 class Client extends Thread {
     70     /**
     71      *  This Class simulates a Client Thread
     72      */
     73     private int id;
     74     private PipedOutputStream pout;
     75     
     76     public Client(int id,PipedOutputStream pout) {
     77         this.id = id;
     78         this.pout = pout;
     79         start();
     80     }
     81     public void run() {
     82         try {
     83             for (int i=0;i<100;i++) {
     84                 String str = this+" obtains the console
    ";
     85                 pout.write(str.getBytes());
     86             }
     87             pout.write("over
    ".getBytes());
     88         } catch (Exception e) {
     89             System.err.println("Error 1: "+e);
     90         }
     91     }
     92     public String toString() {
     93         return "client "+(id+1);
     94     }
     95 }
     96 
     97 public class Main {
     98     
     99     public static void main(String[] args) {
    100         PipedOutputStream pout1 = new PipedOutputStream();
    101         PipedOutputStream pout2 = new PipedOutputStream();
    102         try {
    103             new Server(pout1, pout2);
    104             new Client(0,pout1);
    105             new Client(1,pout2);
    106         } catch (Exception e) {
    107             System.err.println("Error 0: "+e);
    108         }
    109     }
    110 }

      The following program implements Spinlock by using Java AtomicBoolean class:

     1 import java.util.concurrent.atomic.*;
     2 
     3 public class Main {
     4     /**
     5      *  This class implements Spinlock Algorithm
     6      */
     7     private static  class Task extends Thread {
     8         /**
     9          *  This class implements a task thread
    10          */
    11         private int idx;
    12         
    13         public Task(int idx) {
    14             this.idx = idx;
    15             start();
    16         }
    17         public void run() {
    18             LOOP:
    19             for (int i=1;i<=3;i++) {
    20                 while (wait[idx].get()&&lock.getAndSet(true));
    21                 System.out.println("	"+this+"  ("+i+")	in Critical Section");
    22                 int next = idx;
    23                 for (int j=1;j<NUM;j++) {
    24                     next = (next+1)%NUM;
    25                     if (wait[next].get()) {
    26                         wait[next].set(false);
    27                         continue LOOP;
    28                     }
    29                 }
    30                 lock.set(false);
    31             }
    32         }
    33         public String toString() {
    34             return "Task "+(idx+1);
    35         }
    36     }
    37     
    38     private static final int NUM = 50;
    39     private static AtomicBoolean lock;
    40     private static AtomicBoolean[] wait;
    41     
    42     public static void main(String[] args) {
    43         lock = new AtomicBoolean(false);
    44         wait = new AtomicBoolean[NUM];
    45         for (int i=0;i<NUM;i++) {
    46             wait[i] = new AtomicBoolean(false);
    47         }
    48         Task[] task = new Task[NUM];
    49         for (int i=0;i<NUM;i++) {
    50             task[i] = new Task(i);
    51         }
    52         for (int i=0;i<NUM;i++) {
    53             try {
    54                 task[i].join();
    55             } catch (InterruptedException e) {
    56                 e.printStackTrace();
    57             }
    58         }
    59     }
    60 }

      As the first demo of Java Semaphores, the following program solves the classical Sleeping Barber Problem.

      1 import java.util.concurrent.atomic.*;
      2 import java.util.concurrent.*;
      3 import java.util.*;
      4 
      5 public class Main {
      6     /**
      7      * This class simulates Sleeping Barber Problem
      8      */
      9     private static class Barber extends Thread{
     10         /**
     11          *  This class simulates a barber
     12          */
     13         
     14         public Barber() {
     15             start();
     16         }
     17         public void run() {
     18            try {
     19               while(num.get()>0) {
     20                    task.acquire();
     21                    service.release();
     22                    TimeUnit.MILLISECONDS.sleep(servTime);
     23                }
     24            } catch (Exception e) {
     25                e.printStackTrace();
     26            }
     27         }
     28     }
     29     private static class Customer extends Thread{
     30         /**
     31          *  This class simulates a customer
     32          */
     33         private int idx;
     34         
     35         public Customer(int idx) {
     36             this.idx = idx;
     37             start();
     38         }
     39         public void run() {
     40             try {
     41                 mutex.acquire();
     42                 if (chair>0) {
     43                     chair--;
     44                     mutex.release();
     45                 } else {
     46                     synchronized(this) {
     47                         System.out.println("	"+this+" leaves");
     48                     }
     49                     mutex.release();
     50                     num.getAndDecrement();
     51                     return;
     52                 }
     53                 synchronized(this) {
     54                     System.out.println("	"+this+" sits and waits");
     55                 }
     56                 task.release();
     57                 service.acquire();
     58                 num.getAndDecrement();
     59                 synchronized(this) {
     60                     System.out.println("	"+this+" is served");
     61                 }
     62                 TimeUnit.MILLISECONDS.sleep(servTime);
     63                 mutex.acquire();
     64                 chair++;
     65                 mutex.release();
     66             } catch (InterruptedException e) {
     67                 e.printStackTrace();
     68             }
     69         }
     70         public String toString() {
     71             return "Customer  # "+idx+"	";
     72         }
     73     }
     74     
     75     private static Semaphore mutex;
     76     private static int chair = 10;
     77     private static AtomicInteger num;
     78     private static Semaphore task;
     79     private static Semaphore service;
     80     private static int servTime = 25;
     81     private static int custTime = 20;
     82     
     83     public static void main(String[] argds) {
     84         mutex = new Semaphore(1);
     85         task = new Semaphore(0);
     86         service = new Semaphore(0);
     87         num = new AtomicInteger(50);
     88         System.out.println("Number of Chairs:	"+chair);
     89         System.out.println("Number of Customers:	"+num);
     90         System.out.println();
     91         int numVal = num.get();
     92         Barber barber = new Barber();
     93         Customer[] cust = new Customer[numVal];
     94         try {
     95              for (int i=0;i<numVal;i++) {
     96                  cust[i] = new Customer(i);
     97                  int t = (new Random()).nextInt(custTime);
     98                  TimeUnit.MILLISECONDS.sleep(t);
     99              }
    100              barber.join();
    101              for (int i=0;i<numVal;i++) {
    102                  cust[i].join();
    103              }
    104         } catch (Exception e) {
    105             e.printStackTrace();
    106         }
    107     }
    108 }

      The second example simulates Smoking Lounge Problem, where a smoker cannot smoke when a non-smoker stays in the lounge, and a non-smoker will not enter the lounge as long as there is a smoker smoking in the lounge.

      1 import java.util.concurrent.atomic.*;
      2 import java.util.concurrent.*;
      3 import java.util.*;
      4 
      5 public class Main {
      6     /**
      7      *  This class simulates Lounge Problem
      8      */
      9     private static class Smoker extends Thread{
     10         /**
     11          *  This class simulates a smoker
     12          */
     13         private int idx;
     14         
     15         public Smoker(int idx) {
     16             this.idx = idx;
     17             start();
     18         }
     19         public void run() {
     20             try {
     21                 System.out.println("	"+this+" comes in");
     22                 wait.acquire();
     23                 if (smkCnt.getAndIncrement()==0) {
     24                     semp.acquire();
     25                 }
     26                 wait.release();
     27                 System.out.println("	"+this+" smokes");
     28                 int t = (new Random()).nextInt(10);
     29                 TimeUnit.MILLISECONDS.sleep(t);
     30                 System.out.println("	"+this+" goes out");
     31                 if (smkCnt.decrementAndGet()==0) {
     32                     semp.release();
     33                 }
     34             } catch (Exception e) {
     35                 e.printStackTrace();
     36             }
     37         }
     38         public String toString() {
     39             return "Smoker # "+idx+" ";
     40         }
     41     }
     42     private static class Nonsmk extends Thread {
     43         /**
     44          * This class simulates a non-smoker
     45          */
     46         private int idx;
     47         
     48         public Nonsmk(int idx) {
     49             this.idx = idx;
     50             start();
     51         }
     52         public void run() {
     53             try {
     54                 wait.acquire();
     55                 if (nonCnt.getAndIncrement()==0) {
     56                     semp.acquire();
     57                 }
     58                 wait.release();
     59                 System.out.println("	"+this+" comes in");
     60                 int t = (new Random()).nextInt(10);
     61                 TimeUnit.MILLISECONDS.sleep(t);
     62                 System.out.println("	"+this+" goes out");
     63                 if (nonCnt.decrementAndGet()==0) {
     64                     semp.release();
     65                 }
     66             } catch (Exception e) {
     67                 e.printStackTrace();
     68             }
     69         }
     70         public String toString() {
     71             return "NonSmk  # "+idx+" ";
     72         }
     73     }
     74     
     75     private static final int num = 100;
     76     private static Semaphore wait;
     77     private static Semaphore semp;
     78     private static AtomicInteger smkCnt;
     79     private static AtomicInteger nonCnt;
     80     
     81     static {
     82         wait = new Semaphore(1);
     83         semp = new Semaphore(1);
     84         smkCnt = new AtomicInteger(0);
     85         nonCnt = new AtomicInteger(0);
     86     }
     87     public static void main(String[] args) {
     88         int smkNum=0, nonNum=0;
     89         Thread[] thread = new Thread[num];
     90         try {
     91             for (int i=0;i<num;i++) {
     92                 int r = (new Random()).nextInt(5);
     93                 if (r<3) {
     94                     thread[i] = new Nonsmk(nonNum++);
     95                 } else {
     96                     thread[i] = new Smoker(smkNum++);
     97                 }
     98                 int t = (new Random()).nextInt(5);
     99                 TimeUnit.MILLISECONDS.sleep(t);
    100             }
    101             for (int i=0;i<num;i++) {
    102                 thread[i].join();
    103             }
    104         } catch (Exception e) {
    105             e.printStackTrace();
    106         }
    107     }
    108 }

      At the end of this article, I wish to generalize the smoking lounge problem above: given num different types of threads, as well as all pairs of i and j such that thread type i and type j cannot get access to the critical section together (possibly i==j), describe the behavior of each type of thread so that all of them can work orderly without deadlock or starvation.

      The input of the program should comprise: (1) one integer num indicating the number of thread types; (2) num integers indicating the number of each type of threads; (3) one integer N indicating the number of following input pairs; (4) N integer pairs representing the thread types that cannot coexist in the critical section.

      As a matter of fact, this problem is a generalization of many classical problems such as Reader-Writer Problem, Baboon Crossing Problem, and Search/Insert/Delete Problem. For example, we assume there are 100 threads to search, 50 threads to insert and 20 threads to delete, then the input should be:

    100
    20
    0 2
    1
    2
    2

      The following program is a naive general solution that I have come up with:

      1 import java.util.concurrent.atomic.*;
      2 import java.util.concurrent.*;
      3 import java.util.*;
      4 import java.io.*;
      5 
      6 class Input {
      7     private Scanner in;
      8     private StringTokenizer tok;
      9     
     10     public Input() {
     11         in = new Scanner(new BufferedInputStream(System.in));
     12     }
     13     public String nextString() {
     14         while  (tok==null||!tok.hasMoreTokens()) {
     15             tok = new StringTokenizer(in.nextLine());
     16         } 
     17         return tok.nextToken();
     18     }
     19     public int nextInt() {
     20         while  (tok==null||!tok.hasMoreTokens()) {
     21             tok = new StringTokenizer(in.nextLine());
     22         } 
     23         return Integer.parseInt(tok.nextToken());
     24     }
     25     public double nextDouble() {
     26         while  (tok==null||!tok.hasMoreTokens()) {
     27             tok = new StringTokenizer(in.nextLine());
     28         } 
     29         return Double.parseDouble(tok.nextToken());
     30     }
     31     public void close() {
     32         in.close();
     33     }
     34 }
     35 
     36 class CSP {
     37     private class Task extends Thread {
     38         private int type;
     39         
     40         public Task(int type) {
     41             this.type = type;
     42         }
     43         public void run() {
     44             try {
     45                 sempAcquire();
     46                 System.out.println("	"+this+" is working.");
     47                 sempRelease();
     48             } catch (Exception e) {
     49                 System.err.println("TASK RUN Error: "+e);
     50             }
     51         }
     52         private void sempAcquire() throws InterruptedException {
     53             wait.acquire();
     54             if (mutex[type][type]) {
     55                 semp[type][type].acquire();
     56             }
     57             if (cnt[type].getAndIncrement()==0){
     58                 for (int i=0;i<type;i++) {
     59                     if (mutex[type][i]) {
     60                         semp[type][i].acquire();
     61                     }
     62                 }
     63                 for (int i=type+1;i<num;i++) {
     64                     if (mutex[i][type]) {
     65                         semp[i][type].acquire();
     66                     }
     67                 }
     68             }
     69             wait.release();
     70         }
     71         private void sempRelease() {
     72             if (cnt[type].getAndDecrement()==1){
     73                 for (int i=num-1;i>type;i--) {
     74                     if (mutex[i][type]) {
     75                         semp[i][type].release();
     76                     }
     77                 }
     78                 for (int i=type-1;i>=0;i--) {
     79                     if (mutex[type][i]) {
     80                         semp[type][i].release();
     81                     }
     82                 }
     83             }
     84             if (mutex[type][type]) {
     85                 semp[type][type].release();
     86             }
     87         }
     88         public String toString() {
     89             int idxVal = idx[type].getAndIncrement();
     90             return "Task "+type+" #"+idxVal;
     91         }
     92     }
     93     
     94     private int num;
     95     private Task[][] taskArr;
     96     private AtomicInteger[] cnt;
     97     private AtomicInteger[] idx;
     98     private Semaphore wait;
     99     private Semaphore[][] semp;
    100     private boolean mutex[][];
    101     
    102     public CSP(int num) {
    103         this.num = num;
    104         taskArr = new Task[num][];
    105         cnt = new AtomicInteger[num];
    106         idx = new AtomicInteger[num];
    107         for (int i=0;i<num;i++) {
    108             cnt[i] = new AtomicInteger(0);
    109             idx[i] = new AtomicInteger(0);
    110         }
    111         try {
    112             wait = new Semaphore(1);
    113             semp = new Semaphore[num][];
    114             mutex = new boolean[num][];
    115             for (int i=0;i<num;i++) {
    116                 semp[i] = new Semaphore[i+1];
    117                 mutex[i] = new boolean[i+1];
    118             }
    119         } catch (Exception e) {
    120             System.err.println("CSP INIT Error: "+e);
    121         }
    122     }
    123     public void genThread(int type,int n) {
    124         taskArr[type] = new Task[n];
    125         for (int i=0;i<n;i++) {
    126             taskArr[type][i] = new Task(type);
    127         }
    128     }
    129     public void setMutex(int i,int j) {
    130         if (j>i) {
    131             i += j;
    132             j = i-j;
    133             i -= j;
    134         }
    135         mutex[i][j] = true;
    136         try {
    137             semp[i][j] = new Semaphore(1);
    138         } catch (Exception e) {
    139             System.err.println("CSP SETMUTEX Error: "+e);
    140         }
    141     }
    142     public void start() {
    143         class Pair {
    144             public int type,idx;
    145             public Pair(int i,int j) {
    146                 type = i;
    147                 idx = j;
    148             }
    149         }
    150         List<Pair> q = new LinkedList<Pair>();
    151         for (int i=0;i<num;i++) {
    152             for (int j=0;j<taskArr[i].length;j++) {
    153                 q.add(new Pair(i,j));
    154             }
    155         }
    156         Collections.shuffle(q,new Random());
    157         while (!q.isEmpty()) {
    158             Pair item = q.remove(0);
    159             taskArr[item.type][item.idx].start();
    160         }
    161     }
    162     public void join() {
    163         try {
    164             for (int i=0;i<num;i++) {
    165                 for (int j=0;j<taskArr[i].length;j++) {
    166                     taskArr[i][j].join();
    167                 }
    168             }
    169         } catch (Exception e) {
    170             System.err.println("CSP JOIN Error: "+e);
    171         }
    172     }
    173 }
    174 
    175 
    176 public class Main {
    177     
    178     public static void main(String[] args) {
    179         Input in = new Input();
    180         int n = in.nextInt();
    181         CSP csp = new CSP(n);
    182         for (int i=0;i<n;i++) {
    183             csp.genThread(i,in.nextInt());
    184         }
    185         int m = in.nextInt();
    186         for (int i=0;i<m;i++) {
    187             csp.setMutex(in.nextInt(),in.nextInt());
    188         }
    189         in.close();
    190         System.out.println("Critical Section Problem:");
    191         csp.start();
    192         csp.join();
    193     }
    194 }

     

    References:

      1. Nutt, Gary. Operating Systems: A Modern Perspective[M].北京:机械工业出版社, 2004-02

      2. Eckel, Bruce. Thinking in Java[M]. 北京:机械工业出版社, 2007-06

  • 相关阅读:
    数据结构与算法JavaScript (一) 栈
    js架构设计模式——前端MVVM框架设计及实现(二)
    js架构设计模式——前端MVVM框架设计及实现(一)
    js架构设计模式——MVC,MVP 和 MVVM 的图示及简单明了的区别说明
    js架构设计模式——你对MVC、MVP、MVVM 三种组合模式分别有什么样的理解?
    js面向对象oop编程
    js模块化开发——前端模块化
    SPRING 集成 activemq 的 topic 模式
    linux yum 本地源配置
    ORACLE 导入的问题
  • 原文地址:https://www.cnblogs.com/DevinZ/p/4411446.html
Copyright © 2020-2023  润新知