进程与线程
1、概念
线程是进程的子任务,多个线程共享进程的内存。
2、进程间通信
- 管道(pipe)及命名管道(named pipe):管道可用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
- 信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
- 消息队列:消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息;
- 共享内存:可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等;
- 信号量:主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段;
- 套接字:这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。
3、同步与互斥
由于进程是并发执行的,这是一个前提。
- 同步:协调工作次序。譬如A、B两个进程分别进行读写数据的操作,那么写数据应该发生在读数据之前,由于异步性的存在,可能会发生先读后写的情况,而由于此时缓冲区为空,该读数据进程就会被阻塞。
(另一种说法:同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。) - 互斥:共享系统资源。有些资源在一个时间段内只允许一个进程使用。(比如一些系统资源打印机,这些资源称之为临界资源)
4、线程的互斥与同步
- 互斥:互斥量、读写锁、自旋锁
- 同步:条件变量、信号量、轮询结合互斥量、屏障
5、进程、线程同步的方式
- 线程:原子操作、信号量机制、自旋锁管程、会合、分布式系统
- 进程:
* 互斥量 Synchronized/Lock:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。
* 信号量 Semphare:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量事件(信号),Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作
6、互斥量与自旋锁的区别
都是用于多线程互斥的场景下。
- 自旋锁是一种非阻塞锁,也就是说,如果某线程需要获取自旋锁,但该锁已经被其他线程占用时,该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取自旋锁。
- 互斥量是阻塞锁,当某线程无法获取互斥量时,该线程会被直接挂起,该线程不再消耗CPU时间,当其他线程释放互斥量后,操作系统会激活那个被挂起的线程,让其投入运行。
- 两种锁适用于不同场景:如果是多核处理器,如果预计线程等待锁的时间很短,短到比线程两次上下文切换时间要少的情况下,使用自旋锁是划算的。如果是多核处理器,如果预计线程等待锁的时间较长,至少比两次线程上下文切换的时间要长,建议使用互斥量。如果是单核处理器,一般建议不要使用自旋锁。因为,在同一时间只有一个线程是处在运行状态,那如果运行线程发现无法获取锁,只能等待解锁,但因为自身不挂起,所以那个获取到锁的线程没有办法进入运行状态,只能等到运行线程把操作系统分给它的时间片用完,才能有机会被调度。这种情况下使用自旋锁的代价很高。如果加锁的代码经常被调用,但竞争情况很少发生时,应该优先考虑使用自旋锁,自旋锁的开销比较小,互斥量的开销较大。
7、生产者消费者模型
如果共享数据区已满的话,阻塞生产者继续生产数据放置入内;
如果共享数据区为空的话,阻塞消费者继续消费数据;