一次仅允许一个进程使用的资源称为临界资源。
对临界资源进行访问的那段代码称为临界区。
同步: 多个进程因为合作产生的直接制约关系,使得进程有一定的先后执行关系。
互斥: 多个进程在同一时刻只有一个进程能进入临界区。
进程之间经常会存在互斥和同步两种关系.为了有效的处理这两种情况,提出了信号量 (semaphore)和PV操作。
信号量是一个整形变量,可以对其执行PV操作。
PV操作被设计成原语,不可分割。
如果信号量的取值只能为0或1,那么就成为了互斥量。
问题描述
使用一个缓冲区来存放物品,只有缓冲区没有满,生产者才可以放入物品;只有缓冲区不为空,消费者才可以拿走物品。
解释
缓冲区处于临界资源,因此,需要一个互斥量mutex来控制缓冲区的互斥访问。
为了同步生产者和消费者的行为,需要记录缓冲区中物品的数量。数量可以用信号量来统计,需要两个信号量:empty记录空缓冲区的数量,full记录满缓冲区的数量。
empty信号量是在生产者进程中使用,当empty不为零时,生产者才能放入物品;
full信号量是在消费者进程中使用的,方full信号量不为0时,消费者才可以取走物品。
注意
不能对缓冲区先进行加锁再测试信号量。即不能先P(mutex)再P(empty)。否则可能会出现如下情况。
生产者对缓冲区加锁,执行P(mutex)在执行P(empty)操作,发现empty=0,此时生产者睡眠。
消费者不能进入临界区,因为生产者对缓冲区加锁了,消费者就无法执行V(empty)操作,empty永远都是0,导致生产者永远等待,不释放锁,消费者也因此永远等待。
#define N 100
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = N;
semaphore full = 0;
void producer() {
while(TRUE) {
int item = produce_item();
down(&empty);
down(&mutex);
insert_item(item);
up(&mutex);
up(&full);
}
}
void consumer() {
while(TRUE) {
down(&full);
down(&mutex);
int item = remove_item();
consume_item(item);
up(&mutex);
up(&empty);
}
}
描述
允许多个进程同时对数据进行读操作,但是不允许读和写以及写和写同时发生。
解决
typedef int semaphore;
semaphore count_mutex = 1;
semaphore data_mutex = 1;
int count = 0;
void reader() {
while(TRUE) {
// ---------------------------
down(&count_mutex);
count++;
if(count == 1) down(&data_mutex); // 第一个读者需要对数据进行加锁,防止写进程访问
up(&count_mutex);
// ---------------------------
read();
down(&count_mutex);
count--;
if(count == 0) up(&data_mutex);
up(&count_mutex);
// ---------------------------
}
}
void writer() {
while(TRUE) {
down(&data_mutex);
write();
up(&data_mutex);
}
}
管道是通过调用 pipe 函数创建的,pipefd[0] 用于读,pipefd[1] 用于写。
#include
int pipe(int pipefd[2]);
调用pipe函数,会在内核中开辟出一块缓冲区用来进行进程间通信,这块缓冲区称为管道,它有一个读端和一个写端。
可以通过read(pipefd [0]);或者write(pipefd [1]) 操作管道
通信步骤
特点
匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了命名管道(FIFO)。
命名管道不同于匿名管道之处在于它提供了一个路径名与之关联,以命名管道的文件形式存在于文件系统中,这样,即使与命名管道的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过命名管道相互通信,因此,通过命名管道不相关的进程也能交换数据。
命名管道遵循先进先出原则,对匿名管道及命名管道的读总是从开始处返回数据,对它们的写则把数据添加到末尾。命名管道的名字存在于文件系统中,内容存放在内存中。
信号是Linux系统中用于进程间互相通信或者操作的一种机制,信号可以在任何时候发给某一进程,而无需知道该进程的状态。
信号量本质上是一个计数器,用于多进程对共享数据对象的读取,它和管道有所不同,它不以传送数据为主要目的,它主要是用来保护共享资源,使得资源在一个时刻只有一个进程独享。
借助套接字,要进行通信的进程,可以在本地单机上进行,也可以跨网络进行。
它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。