auto commit

This commit is contained in:
CyC2018 2018-03-20 14:13:39 +08:00
parent 02b5b4c5b6
commit ce47dcaa49

View File

@ -216,7 +216,7 @@
### 3. 信号量 ### 3. 信号量
**信号量Semaphore** 是一个整型变量,可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作。 信号量Semaphore是一个整型变量可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作。
- **down** : 如果信号量大于 0 ,执行 -1 操作;如果信号量等于 0进程睡眠等待信号量大于 0 - **down** : 如果信号量大于 0 ,执行 -1 操作;如果信号量等于 0进程睡眠等待信号量大于 0
- **up** :对信号量执行 +1 操作,唤醒睡眠的进程让其完成 down 操作。 - **up** :对信号量执行 +1 操作,唤醒睡眠的进程让其完成 down 操作。
@ -241,13 +241,13 @@ void P2() {
} }
``` ```
#### 使用信号量实现生产者-消费者问题 <font size=3> **使用信号量实现生产者-消费者问题** </font> </br>
使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品;只有缓冲区不为空,消费者才可以拿走物品。 题目描述:使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品;只有缓冲区不为空,消费者才可以拿走物品。
需要使用一个互斥量 mutex 来对缓冲区这个临界资源进行互斥访问。 因为缓冲区属于临界资源,因此需要使用一个互斥量 mutex 来控制对缓冲区的互斥访问。
为了同步生产者和消费者的行为需要记录缓冲区中物品的数量。数量可以使用信号量来进行统计这里需要使用两个信号量empty 记录空缓冲区的数量full 记录满缓冲区的数量。其中empty 信号量是在生产者进程中使用,当 empty 不为 0 时生产者才可以放入物品full 信号量是在消费者进中使用,当 full 信号量不为 0 时,消费者才可以取走物品。 为了同步生产者和消费者的行为需要记录缓冲区中物品的数量。数量可以使用信号量来进行统计这里需要使用两个信号量empty 记录空缓冲区的数量full 记录满缓冲区的数量。其中empty 信号量是在生产者进程中使用,当 empty 不为 0 时生产者才可以放入物品full 信号量是在消费者进中使用,当 full 信号量不为 0 时,消费者才可以取走物品。
注意,不能先对缓冲区进行加锁,再测试信号量。也就是说,不能先执行 down(mutex) 再执行 down(empty)。如果这么做了,那么可能会出现这种情况:生产者对缓冲区加锁后,执行 down(empty) 操作,发现 empty = 0此时生产者睡眠。消费者不能进入临界区因为生产者对缓冲区加锁了也就无法执行 up(empty) 操作empty 永远都为 0那么生产者和消费者就会一直等待下去造成死锁。 注意,不能先对缓冲区进行加锁,再测试信号量。也就是说,不能先执行 down(mutex) 再执行 down(empty)。如果这么做了,那么可能会出现这种情况:生产者对缓冲区加锁后,执行 down(empty) 操作,发现 empty = 0此时生产者睡眠。消费者不能进入临界区因为生产者对缓冲区加锁了也就无法执行 up(empty) 操作empty 永远都为 0那么生产者和消费者就会一直等待下去造成死锁。
@ -285,7 +285,7 @@ void consumer() {
使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。 使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。
c 语言不支持管程,下面的示例代码使用了类 Pascal 语言来描述管程。示例代码的管程提供了 insert() 和 remove() 方法,客户端代码通过调用这两个方法来解决生产者-消费者问题。 c 语言不支持管程,下面的示例代码使用了类 Pascal 语言来描述管程。示例代码的管程提供了 insert() 和 remove() 方法,客户端代码通过调用这两个方法来解决生产者-消费者问题。
```pascal ```pascal
monitor ProducerConsumer monitor ProducerConsumer
@ -306,11 +306,12 @@ end monitor;
管程有一个重要特性:在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,否者其它进程永远不能使用管程。 管程有一个重要特性:在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,否者其它进程永远不能使用管程。
管程引入了 **条件变量** 以及相关的操作:**wait()** 和 **signal()** 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来另一个进程持有。signal() 操作用于唤醒被阻塞的进程。 管程引入了 **条件变量** 以及相关的操作:**wait()** 和 **signal()** 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来另一个进程持有。signal() 操作用于唤醒被阻塞的进程。
#### 使用管程实现生成者-消费者问题 <font size=3> **使用管程实现生成者-消费者问题** </font><br>
```pascal ```pascal
// 管程
monitor ProducerConsumer monitor ProducerConsumer
condition full, empty; condition full, empty;
integer count := 0; integer count := 0;
@ -333,6 +334,7 @@ monitor ProducerConsumer
end; end;
end monitor; end monitor;
// 生产者客户端
procedure producer procedure producer
begin begin
while true do while true do
@ -342,6 +344,7 @@ begin
end end
end; end;
// 消费者客户端
procedure consumer procedure consumer
begin begin
while true do while true do
@ -360,7 +363,7 @@ end;
写进程在管道的尾端写入数据,读进程在管道的首端读出数据。管道提供了简单的流控制机制,进程试图读空管道时,在有数据写入管道前,进程将一直阻塞。同样地,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。 写进程在管道的尾端写入数据,读进程在管道的首端读出数据。管道提供了简单的流控制机制,进程试图读空管道时,在有数据写入管道前,进程将一直阻塞。同样地,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。
Linux 中管道通过空文件实现。 Linux 中管道通过空文件实现。
管道有三种: 管道有三种:
@ -370,7 +373,7 @@ Linux 中管道是通过空文件来实现。
### 2. 信号量 ### 2. 信号量
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制防止一个进程正在访问共享资源时,其它进程也访问该资源。主要作为进程间以及同一进程内不同线程之间的同步手段。 信号量是一个计数器,可以用来控制多个进程对共享资源的互斥访问,主要作为进程间以及同一进程内不同线程之间的同步手段。
### 3. 消息队列 ### 3. 消息队列