Q1: 进程间的通信方式
1. 匿名管道
管道是通过调用 pipe 函数创建的,fd[0] 用于读,fd[1] 用于写
1 | int pipe(int fd[2]); |
存在形式:
无名管道:只存在于内存中的文件
使用限制:
- 只支持半双工(单向交替传输)
- 只能在父子进程或兄弟进程中使用
2. 命名管道
解决了匿名管道的只能在父子进程中使用的限制。
存在形式:
命名管道:存在于实际的磁盘介质或者文件系统
1 | #include <sys/stat.h> |
FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。
管道的实现机制:
管道是由内核管理的一个缓冲区,这个缓冲区被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。
3. 消息队列
消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。 进程控制块(PCB)中有对应的字段会保存对应消息队列的标识符.
存在形式:
消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。
消息队列的优点:
- 可以对消息随机读取,而不是像管道那样只能FIFO
- 比起管道, 消息队列能存储的信息更多更丰富
4. 信号量
信号量可以理解成一个计数器,用于解决多个进程访问共享资源时的同步问题。
5. 共享内存
使多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。 这种方式需要依靠某种同步操作,例如:互斥锁和信号量等。
6. 套接字
此方法主要用于不在同一台机器上的进程间的通信,例如客户端的一个进程和服务端的一个进程进行通信。
Q2: 线程间的同步方式有哪些
1. 互斥量(mutex) (抢占式同步)
就是上锁,在java中主要就是 synchronized 和 各种Lock.
2. 信号量(Semphore) (非抢占式同步)
允许多个线程访问同一个资源,但需要控制同一时刻访问此资源的最大线程数量
3. Java对管程的实现( wait / notify )
通过wait和notify来实现同步
Q3:死锁产生的条件
1. 互斥
每一个资源只能分给一个进程.
2. 占用和等待
已经得到了某个资源的进程可以再请求新的资源. 并且可以在持有一些资源的状态下去等待暂时无法获取的资源
3. 不可抢占
已经分配给一个进程的资源,在这个进程没有使用完或主动释放之前,都不能被其他进程获取.
4. 环路等待
Q4: 解决死锁的策略:
1. 鸵鸟策略(解决策略就是不去解决)
因为解决死锁的代价会比较大,且死锁发生的概率又比较小,并且死锁也不会对用户造成致命影响的话,那么就忽略它好了..
2. 死锁检测与死锁恢复
不试图阻止死锁,而是当检测到死锁发生的时候,采取一些措施进行一个恢复
检测到死锁后的恢复策略:
- 利用抢占恢复
- 利用回滚恢复
- 通过杀死进程恢复
其实就是破坏死锁的必要条件中的一个就行了..
3. 死锁预防
在程序运行之前就预防发生死锁,就是破坏死锁产生的必要条件中的一个就行。
例如:
- 给资源统一编号,进程只能按编号顺序来请求资源,破坏了环路等待;
- 分配资源时,一次性把所有资源都分配出去, 破坏了占有并等待;
4. 死锁避免
在程序运行时,避免发生死锁。 使用银行家算法,保证在资源分配后依然能让系统处于安全状态.. 如果不安全的话就拒绝分配.