跳到主要内容

进程同步

并发执行的进程在访问共享资源时需要同步机制来保证正确性。本节介绍临界区问题的解法以及常用的同步原语。

临界区与互斥

一段访问共享资源的代码称为临界区(critical section)。临界区问题要求满足:

  1. 互斥:任意时刻最多一个进程在临界区内。
  2. 前进:无进程在临界区时,申请进入的进程应尽快进入。
  3. 有限等待:进程提出申请后,等待进入临界区的时间有限。

常见的互斥实现包括硬件指令(test-and-setcompare-and-swap)和软件算法(Dekker、Peterson)。

信号量

信号量(Semaphore)由 Dijkstra 提出,是一个整型计数器加上 P(wait)和 V(signal)两个原子操作。

  • 二元信号量初值为 1,用于互斥。
  • 计数信号量初值大于 1,用于控制对有限资源的并发访问。
wait(S):
while (S <= 0) ; // 忙等
S = S - 1;

signal(S):
S = S + 1;

互斥锁与条件变量

互斥锁(mutex)提供加锁/解锁原语,通常用于保护临界区。条件变量(condition variable)允许线程在某个条件未满足时阻塞,并在条件可能改变时被唤醒。

条件变量必须与互斥锁配合使用。常见 API:

pthread_mutex_lock(&mtx);
while (!condition) pthread_cond_wait(&cv, &mtx);
pthread_mutex_unlock(&mtx);

生产者-消费者问题

该问题中,生产者向缓冲区写入数据,消费者从中取出。需要保证缓冲区满时生产者等待,空时消费者等待。

使用计数信号量 emptyfull 和互斥信号量 mutex:

producer:
wait(empty);
wait(mutex);
put(item);
signal(mutex);
signal(full);

consumer:
wait(full);
wait(mutex);
get(item);
signal(mutex);
signal(empty);

该模型体现了「资源计数 + 互斥」的同步组合,是许多高级并发原语的基础。