面试题:进程间通信方式,线程间通信方式

一、进程间通信(IPC,Inter-Process Communication)是指在不同进程间传播或交换信息

1. 无名管道

特点

  • 半双工(数据流向仅有一个方向),具有固定的读端和写端
  • 只能用于父进程或兄弟线程之间通信(具有血缘关系的线程之间)
  • 一种特殊文件,可以用普通的read、write函数进行读写,但又不是普通文件,不属于任何其它文件系统,仅存在于内存之中
  • 通信的数据是无格式的流并且大小受限

2. 命名管道(先进先出队列)

特点

不同于无名管道之处在于它提供一个与之关联的路径名,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,不相关的进程也能通过FIFO交换数据

FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。如图

3. 消息队列

  • 消息队列,是消息的链接表,存放在内核中。其中的消息具有特定的格式以及特定的优先级
  • 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取

4. 信号量

信号量(semaphore)是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

5. 共享内存

现代操作系统,对于内存管理,采用的是虚拟内存技术,也就是每个进程都有自己独立的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。所以,即使进程 A 和 进程 B 的虚拟地址是一样的,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。但是,如果两个进程通过页表将虚拟地址映射到物理地址时,有一部分物理内存重合了,那么这部分重合的内存就是即共享内存,它可以被两个进程同时看到。在共享内存中,一个进程进行写操作,另一个进程进行读操作,这样它们就可以实现进程间通信。但是,我们要确保一个进程在写的时候不能被读,因此我们使用信号量来实现同步与互斥。

面试题:进程间通信方式,线程间通信方式_第1张图片

 

 

  • 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取
  • 因为多个进程可能会同时操作共享的内存,所以需要进行同步
  • 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问

6. 套接字(socket)

与其他进程通信方式不同,它可用于不同机器间的进程通信

二、Linux线程间通信

操作系统中线程间的通信有两种情况:

  1. 不同进程的线程之间进行通信,由于两个线程只能访问自己所属进程的地址空间和资源,故等同于进程间的通信。(上面已经介绍了)
  2. 同一个进程中的两个线程进行通信。

由于同一进程中的线程之间有共享内存,因此它们之间的通信是通过共享内存实现的。

三、Java线程间通信

从根本上来说,线程间的通信有两种方式:

  • 一种是在共享内存的并发模型中,线程之间通过读-写共享内存来实现通信(公共状态)
  • 一种是在消息传递的并发模型里,线程之间通过发送消息来进行通信(没有公共状态)

而Java的并发采用的是共享内存模型,所以Java线程之间的通信是基于共享内存实现的。具体来讲Java线程之间的通信由Java内存模型控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。如果线程A与B之间要通信的话,必须经历下面两个步骤:

  1. 线程A把本地内存中更新过的共享变量刷新到主内存中去。
  2. 线程B到住内存中去读取线程A之前更新过的共享变量。(如图)

现在问题来了,假设共享内存中的共享变量a,如果多个线程同时读a,不会出现任何问题,但是如果这些线程中有至少一个线程对a执行写操作,就可能出现数据不一致问题,也就是线程不安全了,那这是绝对不允许的。怎么办?答案就是依靠线程同步,来保证即使多个线程并发访问共享变量时,依然能够保证数据一致!

所以,就出现了个各种各样的锁呀,并发工具包呀

1. volatile

2. java中的wait()/notify()/notifyAll()

底层是如何通过并发控制保证基于共享内存的通信的正确性和安全性

线程间通信的几种实现方式

线程通信的四种方式

linux基础——linux线程间通信及同步机制总结

你可能感兴趣的:(Java多线程,操作系统,操作系统,多进程,多线程,线程安全)