线程同步与进程同步方式
要注意这里的同步并不是指同时进行的意思,而是按照先后顺序依次进行。 首先了解一下同步与互斥的概念:
- 同步:多个进程因为合作产生的直接制约关系,使得进程有一定的先后执行关系;
- 互斥:多个进程在同一时刻只有一个进程能进入临界区。
一、进程同步方式
进程同步就是控制多个进程按一定顺序执行,而进程间通信(IPC)是在进程间传输信息。它们之间的关系是:进程通信是一种手段,而进程同步是一种目的,。借用知乎某佬的一句话:
不要当那种考试考傻了的书呆子,把“同步”和“通信”的概念分得那么清楚,能通信就一定是一种同步机制,这是显而易见的。
所以面试官问你进程同步的方式时,他的意思其实是让你回答进程间的通信方式。 常用的进程间通信方式:共享内存,信号量,管道,消息队列,套接字。
1. 共享内存
共享内存就是由一个进程创建的,能被其他进程所访问的内存。共享内存是最快的一种IPC方式,因为没有内存拷贝的操作,但需要依靠互斥锁或信号量来实现同步。
2. 信号量
信号量本质就是一个计数器,记录资源能被多少个进程同时访问,用来实现进程之间的互斥与同步,
3. 管道
管道就是内核里的一段缓存,它是半双工的,数据只能向一个方向流动,就是说只能从一段写入数据当作缓存放到内核中,然后从另一端读取,双方需要互相通信时,需要建立起两个管道。管道分为命名管道和匿名管道,命名管道可以用于两个或任意多个进程间通信,匿名管道则只能用于有血缘关系(父子进程、兄弟进程、爷孙进程等)的进程间通信。Linux中的“|”命令就是匿名管道,表示把一个进程的输出作为另一个进程的输入。
4. 消息队列
多个不相干的进程可以通过一个消息队列来传递数据,且传递的是一个有意义的数据结构,而管道只能传递没有意义的字节流,还需要在接收端做解析。消息队列和管道一样是有一个buffer size限制的。
5. 套接字
可用于不同主机之间的进程间通信。
二、线程同步方式
线程同步需要共享资源,也叫做临界资源。对临界资源进行访问的那段代码称为临界区。
线程访问临界区要遵循的规则
(1)空闲让进
(2)忙则等待
(3)有限等待
(4)让权等待 (整形信号量机制不满足)
常用的线程同步方式有四种:互斥锁、读写锁、条件变量、信号量。
1. 互斥锁
是线程同步最常用的一种方式,多线程访问临界区时使用。通过互斥锁可以锁定一个代码块,对于被锁定的这个代码块,所有的线程只能串行处理,不能并行处理。
2. 读写锁
读写锁是互斥锁的升级版,所有线程的读操作都是并行的,但写操作是串行的。程序中的读操作越多,读写锁性能就越高,相反,若程序中全是写操作,那么读写锁会退化成互斥锁。
3. 条件变量
条件变量主要用于线程的阻塞。为了安全性,始终与互斥锁一起使用。举个例子:当任务队列为空时,消费者无法消费,使用条件变量把消费者线程阻塞住,等待生产者生产出任务后,再唤醒一个或多个被条件变量阻塞的消费者线程;反过来也可以控制生产者生产的上限,当任务队列达到一个上限值时用条件变量阻塞住生产者线程,直到消费者把任务消费后再唤醒被条件变量阻塞的生产者线程。
4. 信号量
信号量也是和互斥锁搭配,用来阻塞线程。
工厂里能容下n个人的房间,需要n把锁n把钥匙挂在门上,这就叫信号量。
5. 自旋锁
自旋锁与互斥锁类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。自旋锁可用于一下情况:锁被持有的时间短,而且线程并不希望在重新调度上花费太多成本。