[Modern OS] InterProcess Communication[1]
Posted hezhiqiangts
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Modern OS] InterProcess Communication[1]相关的知识,希望对你有一定的参考价值。
目录
InterProcess Communication
2.3.1 Race Conditions
2.3.2 Critical Regions
避免 race condition 的关键是防止多个进程同时读写共享资源。
换句话说,需要一个互斥锁mutual exclusion
对共享资源进行访问的部分程序被称为临界区critical section
2.3.3 Mutual Exclusion with Busy Waiting
Disabling Interrupts
缺点:
- 给用户进程关闭中断的权限是不明智的;
- 如果系统是多处理器系统,那么关闭中断只会影响执行了
disable
指令的CPU,运行在其他CPU上的进程依然可以访问共享内存。
Disabling interrupts is often a useful technique within the operating system itself but is not appropriate as a general mutual exclusion mechanism for user processes.
Lock Variables
Strict Alternation
Continuous testing a variable until some value appears is called busy waiting. A lock that uses busy waiting is called a spin lock.
缺点:
- 持续检测变量浪费CPU
- 要求严格有序,否则效率低下
Peterson‘s Solution
#define FALSE 0
#define TRUE 1
#define N 2 /* number of processes */
int turn; /* whose turn is it? */
int interested[N]; /* all values initially 0 (FALSE) */
void enter region(int process) /* process is 0 or 1 */
int other; /* number of the other process */
other = 1 ?process; /* the opposite of process */
interested[process] = TRUE; /* show that you are interested */
turn =process; /* set flag */
while (turn == process && interested[other] == TRUE) /* null statement */ ;
void leave region(int process) /* process: who is leaving */
interested[process] = FALSE; /* indicate departure from critical region */
起初没有进程进入临界区。
进程 0 调用enter_region
。它在interested
数组中的对应元素被设置为 1,然后ture
为 0。由于进程 1 还没有调用过enter_region
,所以enter_region
会立刻返回,进程 0 进入临界区。如果此时进程 1 调用了enter_region
,那么在interested[0]
变为FALSE
之前,它都会等待。
如果两个进程几乎同时调用了enter_region
。那么turn
将会是后一个完成赋值操作的进程的号码。假设此时turn
为 1。两个进程同时到达while
语句,进程 0 将会直接退出,然后进入临界区。进程 1 将会等待,直到进程 0 从临界区退出。
本质上也是一个busy waiting
The TSL Instruction
TSL Test and Set Lock
2.3.4 Sleep and Wakeup
上述方法都需要busy waiting。实际上,本质都是:当有进程需要进入临界区时,首先检查是否能够进入,如果不能进入,那么就会执行一个循环一直进行检测,直到能够进入临界区。
busy waiting不光消耗CPU时间,同时还会有一些bug。比如当发生优先级反转时,已经进入临界区的进程无法释放 lock,导致高优先级的进程永远无法进入临界区。
The Producer-Consumer Problem
也叫做有限缓冲区问题( bounded-buffer problem)。
两个进程共享一个公共的、固定大小的缓冲区。其中一个,生产者,将信息放入buffer,另一个,消费者,从buffer中取出消息。
Trouble arises when the producer wants to put a new item in the buffer, but it is already full. The solution is for the producer to go to sleep, to be awakened when the consumer has removed one or more items. Similarly, if the consumer wants to remove an item from the buffer and sees that the buffer is empty, it goes to sleep until the producer puts something in the buffer and wakes it up.
为了追踪缓冲区中物体的数量,我们需要一个变量count
。
#define N 100 /* number of slots in the buffer */
int count = 0; /* number of items in the buffer */
void producer(void)
int item;
while (TRUE) /* repeat forever */
item = produce item( ); /* generate next item */
if (count == N) sleep( ); /* if buffer is full, go to sleep */
inser t item(item); /* put item in buffer */
count = count + 1; /* increment count of items in buffer */
if (count == 1) wakeup(consumer); /* was buffer empty? */
void consumer(void)
int item;
while (TRUE) /* repeat forever */
if (count == 0) sleep( ); /* if buffer is empty, got to sleep */
item = remove item( ); /* take item out of buffer */
count = count ?1; /* decrement count of items in buffer */
if (count == N ? 1) wakeup(producer); /* was buffer full? */
consume item(item); /* pr int item */
然而对count的访问可能会出问题。当对count的访问不做限制时,就会出现rece condition。缓冲区已经空了,消费者读入count来测试它是否为0。在此时,调度器决定将消费者暂停,然后执行生产者。生产者增加了buffer中物体的数量,增加了count,ok那么现在count应该为1。根据生产者的代码,消费者此时会给消费者发出一个wakeup的消息,然而事实上,由于消费者之前被暂停,所以此时它在逻辑上并没有sleep,所以这个消息将会丢失。
当消费者再次执行时,它根据自己之前读到的count==0,将自己转入sleep。不久之后缓冲区满,生产者也进入sleep,这时,消费者和生产者两者都将永远sleep。
这个问题的本质是:wakeup消息被发送给了一个还没有真正sleep的进程。
2.3.5 Semaphores
1965年,Dijkstra提出使用信号量Semaphore。Semaphore是一个整数变量,当它为0时,表示没有保存任何wakeup信号,当它为其他正整数时,表示一个或者多个wakeup were pending。
Dijkstra提出了两个对信号量的操作,down 和 up。对一个信号量的 down 操作检查信号量的值是否为 0,如果不是 0,那么就减 1。如果是 0,那么进程就会sleep,而且暂时不会将 down 操作执行完。检查值的大小、改变值的大小、以及可能的go to sleep,这些行为都是单个的不可分的 原子操作(atomic action)。一旦对信号量的操作被进行,那么所有其他进程都无法访问该信号量,直到操作完成或者该进程阻塞。
up 操作将信号量的值增加1。如果有多个进程sleeping on that semaphore, unable to complete an earlier down operation, 那么系统将会随机选择一个进程完成它的 down operation。Thus, after an up on a semaphore with processes sleeping on it, the semaphore will still be 0, but there will be one fewer process sleeping on it.
Solving the Producer-Consumer Problem Using Semaphores
信号量的作用是为了解决前文提出的wakeup信号丢失的问题(lost-wakeup)。
#define N 100 /* number of slots in the buffer */
typedef int semaphore; /* semaphores are a special kind of int */
semaphore mutex = 1; /* controls access to critical region */
semaphore empty = N; /* counts empty buffer slots */
semaphore full = 0; /* counts full buffer slots */
void producer(void)
int item;
while (TRUE) /* TRUE is the constant 1 */
item = produce item( ); /* generate something to put in buffer */
down(&empty); /* decrement empty count */
down(&mutex); /* enter critical region */
inser t item(item); /* put new item in buffer */
up(&mutex); /* leave critical region */
up(&full); /* increment count of full slots */
void consumer(void)
int item;
while (TRUE) /* infinite loop */
down(&full); /* decrement full count */
down(&mutex); /* enter critical region */
item = remove item( ); /* take item from buffer */
up(&mutex); /* leave critical region */
up(&empty); /* increment count of empty slots */
consume item(item); /* do something with the item */
This solution uses three semaphores: one called full for counting the number of slots that are full, one called empty for counting the number of slots that are empty, and one called mutex to make sure the producer and consumer do not access the buffer at the same time.
初始值为 1 并且被多个进程使用的信号量,保证了同时只有一个进程可以进入临界区,这种信号量被称为二值信号量(binary semaphores)。
以上是关于[Modern OS] InterProcess Communication[1]的主要内容,如果未能解决你的问题,请参考以下文章
boost::interprocess::string 转换为 char*
提升 interprocess_mutex 复制/移动构造函数?
这些 Boost::Interprocess 组件是不是需要同步?