操作系统读者写者进程实现_问:操作系统三大经典同步问题,你如何复现?

点击蓝色小字关注!  关注一下你就不会有bug! 作为操作系统中的最基本模型,在面试中被要求书写的可能性还是很大的,如果只是伪码,这还是一个简单的问题,但是要你具体实现呢?你会使用什么样的方式来实现这件事情呢?

7298250c3ff07ef14718166b7dde93a1.png

生产者、消费者问题

什么是生产者、消费者问题?

c3b76e266e3d792b6f8352acc4609b06.png

意思很简单,就是生产者给生产链生产,而消费者从生产链中拿出。那关键点已经出来了,问题就在于怎么处理这一条生产链(正规叫法应该叫缓冲区)?

伪码实现

 1// 变量
2list = buffer[n] // 生产链,容量为n
3,mutex = 1 // 互斥使用生产链
4,empty = n // 消费后剩余
5,full = 0 // 生产后容量
6
7// 两个运作对象:及对应动作
8producer:product // 生产者生产
9consumer:consume // 消费者消费
10
11// 两个动作
12product{
13    wait(empty) // 生产链不满
14    wait(mutex)
15    // 生产
16    signal(mutex)
17    signal(full) // 给生产链加一个产品
18}
19consumer{
20    wait(full) // 生产链不为空
21    wait(mutex)
22    // 消费
23    signal(mutex)
24    signal(empty) // 生产链中的产品又被消耗
25}

具体代码实现

 1class ProducerAndConsumer {
2    private final int MAX_LEN = 10;
3    private Queue queue = new LinkedList(); 4    Semaphore producer = new Semaphore(0); 5    Semaphore consumer = new Semaphore(MAX_LEN); 6    Semaphore lock = new Semaphore(1); 7 8    // 生产者 9    class Producer extends Thread {10        @Override11        public void run() {12            while (true) {13                try {14                    consumer.acquire(); // 可消费的数量未满15                    lock.acquire(); // 临界区16                    queue.add(1);17                    System.out.println("consumer size:" + queue.size());18                    Thread.sleep(200);19                } catch (InterruptedException e) {20                    e.printStackTrace();21                } finally {22                    lock.release();23                    producer.release();24                }25            }26        }27    }28    // 消费者29    class Consumer extends Thread {30        @Override31        public void run() {32            while (true) {33                try {34                    producer.acquire(); // 还剩余产品35                    lock.acquire(); // 临界区36                    queue.remove();37                    System.out.println("consumer size:" + queue.size());38                    Thread.sleep(200);39                } catch (InterruptedException e) {40                    e.printStackTrace();41                } finally {42                    lock.release();43                    consumer.release();44                }45            }46        }47    }484950    public static void main(String[] args) {51        ProducerAndConsumer producerAndConsumer = new ProducerAndConsumer();52        Producer producer = producerAndConsumer.new Producer();53        Consumer consumer = producerAndConsumer.new Consumer();54        producer.start();55        consumer.start();56    }57}

哲学家就餐问题

60213063b6682f77a6c520c7cf421d29.png

五把叉子,五个人,如果每个人都拿起了叉子,那么整桌的人必然就没饭吃了,哲学家问题思考的就是这样的一个问题。

伪码实现

 1// 变量
2forks = {1, 1, 1, 1, 1} // 暂定为5人
3
4// 一个被运作对象:以及动作
5fork:handle、release
6Philosopher:thinking、eating
7
8// 动作,eating和thinking是两个Thread.sleep完成
9handle {
10    // 左右手只要有一只被拿起,就需要等待
11    // 如果不等带,就可能每个人只拿一只
12    while(forks[postion] == 0 || forks[(position + 1) % 5] == 0){
13        wait() // 等待
14    }
15    forks[postion] == 0;
16    forks[(position + 1) % 5] == 0;
17}
18
19release {
20    // 吃完以后把东西放下
21    forks[postion] == 1;
22    forks[(position + 1) % 5] == 1;
23}

具体代码实现

 1public class PhilosopherEat {
2    class Philosopher extends Thread {
3        private String name;
4        private Fork fork;
5
6        public Philosopher(String name, Fork fork) {
7            super(name);
8            this.name = name;
9            this.fork = fork;
10        }
11
12        @Override
13        public void run() {
14            // 哲学家需要完成要的一系列动作
15            while (true) {
16                thinking();
17                fork.takeFork();
18                eating();
19                fork.putFork();
20            }
21        }
22
23        public void eating() {
24            System.out.println("I am Eating:" + name);
25            try {
26                //模拟吃饭
27                sleep(1000);
28            } catch (InterruptedException e) {
29                // TODO Auto-generated catch block
30                e.printStackTrace();
31            }
32        }
33
34        public void thinking() {
35            System.out.println("I am Thinking:" + name);
36            try {
37                //模拟思考
38                sleep(1000);
39            } catch (InterruptedException e) {
40                e.printStackTrace();
41            }
42        }
43    }
44
45    class Fork{
46        // 5根筷子
47        private boolean[] used={false,false,false,false,false,false};
48
49        public synchronized void takeFork(){
50            String name = Thread.currentThread().getName();
51            int i = Integer.parseInt(name);
52            // 如果左右手有一只正被使用就等待
53            while(used[i]||used[(i+1)%5]){
54                try {
55                    wait();
56                } catch (InterruptedException e) {
57                    e.printStackTrace();
58                }
59            }
60            used[i ]= true;
61            used[(i+1)%5]=true;
62        }
63
64        // 同时释放左右手的筷子
65        public synchronized void putFork(){
66            String name = Thread.currentThread().getName();
67            int i = Integer.parseInt(name);
68            used[i ]= false;
69            used[(i+1)%5]=false;
70            notifyAll();
71        }
72    }
73
74    public static void main(String[] args) {
75        PhilosopherEat philosopher = new PhilosopherEat();
76        Fork fork = philosopher.new Fork();
77        philosopher.new Philosopher("0",fork).start();
78        philosopher.new Philosopher("1",fork).start();
79        philosopher.new Philosopher("2",fork).start();
80        philosopher.new Philosopher("3",fork).start();
81        philosopher.new Philosopher("4",fork).start();
82    }
83}

读者写者问题

bded89cd4640ad7201845b4664fbe3fb.png

读者写者问题针对的就是我们的数据问题,你在 wps 打开一个文件,又在 word 打开一个文件势必会看到一个只读的模式会弹出,这就是读者写着问题的具体表现了。

伪码实现

 1// 变量
2readCount // 当前读书的人数
3,readLock // 读者锁
4,writeLock // 写者锁
5
6// 两个对象:及其动作
7Reader:read
8Writer:write
9
10// 动作
11read{
12    p(readLock)
13        if(readCount == 0) p(writeLock) // 第一个读者进入后,就不可修改
14        readCount++
15    v(readLock)
16
17    // 。。。读书
18
19    p(readLock)
20        readCount--
21        if(readCount == 0) v(writeLock) // 最后一个读者走后,可以开始修改
22    v(readLock)
23}
24
25write{
26    p(writeLock)
27    // 。。。修改
28    v(writeLock)
29}

具体代码实现

 1import java.util.concurrent.Semaphore;
2
3public class ReaderAndWriter {
4    public static void main(String[] args) {
5        // 实现写者与写者间、读者与写者间互斥
6        Semaphore wmutex = new Semaphore(1);
7        // 用于改变 readCount 变量时实现互斥
8        Semaphore rmutex = new Semaphore(1);
9        for (int i = 0; i 3; ++i) {
10            new Reader(rmutex, wmutex).start();
11            new Writer(wmutex).start();
12        }
13    }
14}
15
16class Reader extends Thread {
17    private static int total = 0;
18    private int id;
19    private Semaphore rmutex, wmutex;
20    private static int readCount = 0;
21
22    public Reader(Semaphore rmutex, Semaphore wmutex) {
23        id = ++total;
24        this.rmutex = rmutex;
25        this.wmutex = wmutex;
26    }
27
28    @Override
29    public void run() {
30        while (true) {
31            try {
32                rmutex.acquire();
33                // 只有第一个读者进程需要执行 wmutex.p()
34                if (readCount == 0) wmutex.acquire();
35                readCount++;
36                System.out.println(id + " 号读者在读");
37            } catch (Exception e) {
38            } finally {
39                rmutex.release();
40            }
41            // 模拟读书
42            try {
43                Thread.sleep(30);
44            } catch (InterruptedException e) {
45                e.printStackTrace();
46            }
47            // 读书人出去了
48            try {
49                rmutex.acquire();
50                readCount--;
51                System.out.println(id + " 号读者结束阅读:当前还剩 " + readCount + " 位读者在读");
52                if (readCount == 0) wmutex.release();
53            } catch (Exception e) {
54            } finally {
55                rmutex.release();
56            }
57        }
58    }
59}
60
61class Writer extends Thread {
62    private static int total = 0;
63    private int id;
64    private Semaphore wmutex;
65
66    public Writer(Semaphore wmutex) {
67        id = ++total;
68        this.wmutex = wmutex;
69    }
70
71    @Override
72    public void run() {
73        while (true) {
74            try {
75                wmutex.acquire();
76                // 执行写操作
77                System.out.println(id + " 号写者正在写");
78                wmutex.release();
79            } catch (InterruptedException e) {
80                e.printStackTrace();
81            }
82            // 线程休眠一段时间,总不会一直改的
83            try {
84                Thread.sleep(300);
85            } catch (InterruptedException e) {
86                e.printStackTrace();
87            }
88        }
89    }
90}
原文链接 https://juejin.im/post/5e59fe90f265da574657d9e8 1e6426d36cbca26ef6fcd3d07a72a149.gif▼往期精彩回顾▼问懵逼:JVM中类的主动使用与被动使用?什么样的对象才能作为GC ROOT?GC ROOTS 有哪些?

feb6fd63beb7c9829cfe0a3e565a3789.png

1797d4214d98e6d1314fe7a38b201371.png

01284d9b4f7884849f06c40490fdbc32.png点击左下角阅读原文查看历史经典技术问题汇总,看完顺手走一波PYQ呀~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值