0%

操作系统

Q1: 进程间的通信方式

1. 匿名管道

管道是通过调用 pipe 函数创建的,fd[0] 用于读,fd[1] 用于写

1
int pipe(int fd[2]);

存在形式:
无名管道:只存在于内存中的文件

使用限制:

  • 只支持半双工(单向交替传输)
  • 只能在父子进程或兄弟进程中使用
    在这里插入图片描述

2. 命名管道

解决了匿名管道的只能在父子进程中使用的限制。

存在形式:
命名管道:存在于实际的磁盘介质或者文件系统

1
2
3
#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);
int mkfifoat(int fd, const char *path, mode_t mode);

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. 死锁避免

在程序运行时,避免发生死锁。 使用银行家算法,保证在资源分配后依然能让系统处于安全状态.. 如果不安全的话就拒绝分配.