Skip to main content

第五章:进程同步与通信

在多进程操作系统中,多个进程可能会同时访问共享资源。为了保证数据的正确性和系统的稳定性,进程同步与通信成为关键技术。本章将探讨同步的基本概念、经典同步问题以及进程间通信(IPC)机制。

5.1 同步的基本概念

5.1.1 临界区(Critical Section)

临界区是程序中访问共享资源的代码段。同一时刻只能有一个进程进入临界区,否则可能会发生数据不一致的问题。

5.1.2 互斥(Mutual Exclusion)

互斥是保证同一时刻仅有一个进程进入临界区的机制。通过互斥,多个进程不会同时访问共享资源,从而防止数据冲突。

5.1.3 信号量(Semaphore)

信号量是一种用于进程同步的变量,可以用来控制对共享资源的访问。信号量分为:

  • 二值信号量:只取 0 和 1,通常用于实现互斥锁。
  • 计数信号量:可以取多个值,通常用于控制多资源的并发访问。

示例:信号量实现互斥

Semaphore mutex = 1; // 初始值为1

P(mutex); // 申请资源
// 临界区代码
V(mutex); // 释放资源

5.1.4 锁机制(Locks)

锁用于确保在同一时刻只有一个进程可以访问共享资源。例如,自旋锁是一种忙等待的锁,进程在获取锁之前会一直循环检查锁的状态。

5.2 经典同步问题

5.2.1 哲学家进餐问题(Dining Philosophers Problem)

  • 问题描述:五位哲学家围坐在餐桌旁,每人面前有一只叉子。哲学家们需要两只叉子才能进餐。问题在于如何确保不会发生死锁或饥饿。

  • 解决方案:通过信号量或锁机制,避免所有哲学家同时拿起左边的叉子。

5.2.2 生产者-消费者问题(Producer-Consumer Problem)

问题描述:生产者进程生产数据放入缓冲区,消费者进程从缓冲区取出数据。关键是协调两者的速度,确保缓冲区不会溢出或空耗。 解决方案:使用信号量管理缓冲区的空位数和已有数据数。

示例:生产者-消费者模型

Semaphore full = 0;   // 表示缓冲区中已填满的缓冲区数
Semaphore empty = N;  // 表示缓冲区中空闲的缓冲区数
Semaphore mutex = 1;  // 保护对缓冲区的互斥访问

5.3 进程间通信(IPC)

5.3.1 管道(Pipes)

管道是一种半双工通信机制,数据在单个方向上传输。管道通常用于父子进程之间的通信。

示例:使用管道

int fd[2];
pipe(fd); // 创建管道
write(fd[1], "message", 7); // 写入管道
read(fd[0], buffer, 7);     // 从管道读取

5.3.2 消息队列(Message Queues)

消息队列允许进程之间通过发送和接收消息进行通信。与管道不同,消息队列支持更复杂的数据结构。

5.3.3 共享内存(Shared Memory)

共享内存是最快的 IPC 机制,允许多个进程直接访问同一块内存区域。由于直接内存访问,进程间需要同步机制防止数据冲突。

5.3.4 套接字通信(Sockets)

套接字用于网络通信或本地通信,支持跨机器进程间通信。常见于客户端与服务器之间的交互。

总结

本章介绍了进程同步的基本概念与经典问题,并探讨了进程间通信的主要方法。进程同步与通信确保了多进程环境下的数据一致性与系统稳定性,是操作系统设计中的重要组成部分。