进程间同步
进程同步是为了控制多个进程的执行顺序,为了做到进程同步,通常需要进程间通信(IPC),在不同进程之间传递消息,常见的方式有以下几种:
- 管道(pipe):包括匿名管道、流管道和命名管道(FIFO)。速度慢效率低,容量有限,只能用于父子进程
- 信号量(semaphores):不能用来传递复杂消息,只能用于同步
- 共享内存(shared memory):高级方式
- 消息队列(message passing):容量有限,消息的复制耗时,不适于信息量大或操作频繁的场景
- 信号(signal):
- 套接字(socket):网络上不同进程通信
管道
对于匿名管道:
- 半双工即数据只能单向流动,有固定的读端和写端
- 只能在父子进程或兄弟进程间通信
- 可以看作特殊文件并使用read/write读写,只存在于内存中,不属于任何文件系统
对于命名管道:
- 可以在无关进程间交换数据
- 拥有相关联的路径名,以一种特殊设备文件形式存在于文件系统
消息队列
消息队列是存放在内核中的消息链表,由队列ID来标识:
- 消息有特定格式和特定优先级
- 独立于发送和接收进程,进程终止消息队列仍然存在
- 可以根据消息类型有选择地接收信息
信号量
本质上是一个计数器,用来进程间互斥和同步,而非用于存储进程间通信数据。PV原语操作
信号
异步通信方式
共享内存
速度最快,直接对内存存取,需要同步机制,通常与信号量结合使用
socket
不同主机间IPC
线程间同步/通信
线程同步机制有以下几种:
锁机制
- 互斥锁(mutex):排他性访问共享数据,用来保护临界区。某个线程加锁后,其它要加锁的线程将被阻塞,申请失败进入休眠,直到锁被释放。
- 读写锁(ReadWriteLock):用于读者-写者问题,共有三种状态:不加锁、读模式加锁、写模式加锁。每次只有一个线程可以占用写模式的锁,但可以有多个线程占有读模式锁。
- 自旋锁(spinlock):专为多处理器并发引入,不断循环测试锁的状态,申请线程不会休眠,忙等锁。
- 条件变量(condition variables)
全局变量
在各线程共享的堆上,每个线程私有栈
事件event
信号量
- 信号量(semaphores):有更多取值空间,实现更复杂的同步。
信号量和PV原语的使用可归纳为三种情形:
- 把信号量视为加锁标志位,其目的是为了实现对某个唯一的共享数据的互斥访问,如各个进程间的某共享变量,数据库中的某个记录。
共享数据的值与信号量本身的值没有直接关系,信号量的作用仅仅是作为加锁标志位。其特征是信号量初始值为1,然后在一个进程内部对它进行配对的PV操作。1
2
3
4P(mutex); // mutex的初始值为1
访问该共享数据;
V(mutex);
非临界区 - 把信号量视为某种类型的共享资源的剩余个数,目的是实现对这种类型的共享资源的访问,如各种I/O设备。
信号量的取值具有实际意义,即为空闲资源的个数。多个进程可以同时使用这种类型的资源,直到所有空闲资源均已用完。
其特征是信号量的初始值为\(N\geq 1\),然后在一个进程内部对它进行配对的PV操作。1
2
3
4P(resource); // resource的初始值为N
使用该资源;
V(resource);
非临界区 - 把信号量作为进程间同步的工具,利用它来设定两个进程在运行时的先后顺序。比如,它可以是某个共享资源的当前个数,但是由一个进程负责生成该资源,而另一个进程负责消费该资源,由此引发了两个进程间的先后顺序。
其特征是信号量的初始值为\(N\geq 0\),然后在一个进程里对其使用V原语,增加资源个数,而在另一个进程里对其使用P原语,减少资源个数,从而实现两个进程之间的同步关系。
reference
IPC介绍
进程间通信
信号与信号量
线程间同步
https://www.cnblogs.com/meng-chao/p/16323985.html
https://www.cnblogs.com/limich/p/7477079.html