【面经笔记】进程间通信方式、线程同步机制

线程进程的区别:


  • 进程是资源分配的基本单位、线程是调度的基本单位

  • 一个进程可包含多个线程

  • 线程又称轻量级进程:进程间切换代价大,线程间切换代价小

  • 进程有独立的资源,如内存空间,IO资源等,进程中线程共享这些资源


线程上下文切换和进程上下文切换的区别

进程切换分两步
1.切换页目录以使用新的地址空间
2.切换内核栈和硬件上下文。

对于linux来说,线程和进程的最大区别就在于地址空间。
对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的。所以明显是进程切换代价大

线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出。

另外一个隐藏的损耗是上下文的切换会扰乱处理器的缓存机制。简单的说,一旦去切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了。还有一个显著的区别是当你改变虚拟内存空间的时候,处理的页表缓冲(processor’s Translation Lookaside Buffer (TLB))或者相当的神马东西会被全部刷新,这将导致内存的访问在一段时间内相当的低效。但是在线程的切换中,不会出现这个问题。


进程间通信常用有4种方式,以下从简单到复杂:


1.管道(pipe)

匿名/无名管道:
http://blog.csdn.net/shltsh/article/details/46524401
有名/命名管道:
http://blog.csdn.net/shltsh/article/details/46525805

管道是一种具有两个端点的通信通道,一个管道实际上就是只存在在内存中的文件,对这个文件操作需要两个已经打开文件进行,他们代表管道的两端,也叫两个句槟,管道是一种特殊的文件,不属于一种文件系统,而是一种独立的文件系统,有自己的数据结构,根据管道的使用范围划分为无名管道和命名管道。
无名管道用于父进程和子进程之间,通常父进程创建管道,然后由通信的子进程继承父进程的读端点句柄和写端点句柄,或者父进程有读写句柄的子进程,这些子进程可以使用管道直接通信,不需要通过父进程。
当父进程通过fork创建子进程后,父子进程都拥有对管道操作的文件描述符,此时父子进程关闭对应的读写端,使父子进程间形成单向的管道。关闭哪个端要根据具体的数据流向决定。

命名管道,命名管道是为了解决无名管道只能在父子进程间通信而设计的,命名管道是建立在实际的磁盘介质或文件系统(而不是只存在内存中),任何进程可以通过文件名或路径建立与该文件的联系,命名换到需要一种FIFO文件(有先进先出的原则),虽然FIFO文件的inode节点在磁盘上,但仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。

无名管道只能用于具有亲缘关系的进程间的通信命名管道最大的特性就是每个命名管道都有一个路径名与之相关联,从而允许无亲缘关系的任意两个进程间通过命名管道进行通信。


2.事件/信号

信号,用于向进程通知发生异步事件的机制。类似于中断。 内核、进程都可以发送信号, 一次只给进程一个信号,不排队。

事件的触发表示一个操作的完成。
事件包含一个标志位,表示事件时自动重置事件还是手动重置事件。当一个手动重置事件被触发时,所有正在等待该事件的所有线程都将变成可调度状态。当一个自动重置事件被触发时,只有一个正在等待该事件的线程会被变成可调度状态。

当线程成功等到自动重置事件对象时,对象会自动地重置为未触发态。


3.消息队列

详见:http://blog.csdn.net/shltsh/article/details/46538523

消息队列是消息(有类型的一段文本)的链表,每个进程都有一个与之关联的消息队列,消息队列类似于邮箱,有权限的进程可以向消息队列中添加消息,有读权限的进程可以读走消息队列的消息。

消息队列克服了信号承载信息量少,管道只能承载无格式字节流及缓冲区大小受限等缺陷。

消息队列和管道的区别主要有以下两点:一个进程向消息队列写入消息之前,并不需要某个进程在该队列上等待该消息的到达,而管道和FIFO是相反的,进程向其中写消息时,管道和FIFO必需已经打开来读,否则写进程就会阻塞(默认情况下)。
· IPC的持续性不同。管道和FIFO是随进程的持续性,当管道和FIFO最后一次关闭发生时,仍在管道和FIFO中的数据会被丢弃。消息队列是随内核的持续性,即一个进程向消息队列写入消息后,然后终止,另外一个进程可以在以后某个时刻打开该队列读取消息。只要内核没有重新自举,消息队列没有被删除。


4.共享内存

详见:ttp://blog.csdn.net/shltsh/article/details/46566879

管道,命名管道,消息队列。它们的共同点都是通过内核来进行通信。写入数据时,需要把数据从用户空间(用户进程)复制到内核,而从这些IPC读取数据时,又需要把数据从内核复制到用户空间。
共享内存使用方式是将同一个内存区映射到共享它的不同进程的地址空间中,这样这些进程间的通信就不再需要通过内核,只需对该共享的内存区域进程操作就可以了。
共享内存是最快的IPC形式,是针对其他通信方式运行效率低而设计的,往往与其他进程通信方式结合使用,如与信号量结合,来达到进程间的同步与互斥。传递文件最好用共享内存的方式。


线程同步机制:

  • 临界区:

用于多线程的串行化访问公共资源或者一段代码

  • 互斥量:

控制单个线程独享资源。拥有互斥量的线程才能访问资源,互斥量只有一个,故保证不会被多个线程访问。

  • 信号量:

控制有限个数的线程访问共享资源

  • 事件/信号

信号,用于向通知发生异步事件的机制,类似于中断。


互斥量与二元信号量区别:

功能类似,但是互斥量的加锁和解锁必须是同一个线程


临界区与互斥量区别:

使用互斥不仅能够在同一应用程序不同线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享。

互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量 。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。


你可能感兴趣的:(面试题,阿里巴巴面试题)