IPC总结

简单对比

管道:通常只能在相关进程间通信

消息队列:中断的时候无法阻塞地接受数据

信号量:无法在内核态和用户态之间使用

共享内存:需要使用信号量,但是信号量又无法在内核态和用户态之间使用

普通套接字:中断的时候无法阻塞地接受数据

小结:尽量使用管道与FIFO以及记录锁,避免使用消息队列以及信号量,特殊情况下考虑使用共享存储。

管道

管道也是一种文件,可以传送无格式的字节流,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:

  1. 限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不象文件那样不加检验地增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。

  2. 读取进程也可能工作得比写进程快。当所有当前进程数据已被读取时,管道变空。当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。

从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。tee(1)。

未命名管道

只能在两个相关的进程之间使用,这两个相关的进程还要有一个共同的创建了它们的祖先进程。
IPC总结_第1张图片
IPC总结_第2张图片

在shell中可以用管道将前一条命令进程的标准输出与后一条命令的标准输入相连接。
IPC总结_第3张图片

命名管道FIFO

不相关进程也能交换数据

用途:

  • shell命令使用FIFO将数据从一条管道传送到另一条,无需创建中间临时文件。

IPC总结_第4张图片
IPC总结_第5张图片

    mkfifo fifo1
    prog3 < fifo1 &
    prog1 < infile | tee fifo1 | prog2
  • 客户进程-服务器进程应用程序中,FIFO用作汇聚点,在客户进程和服务器进程二者之间传递数据。

IPC总结_第6张图片

消息队列

消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列是随内核持续的。

信号量

  • 死锁

    信号量引入的潜在的运行时错误

    产生“死锁”的必要条件:

    1. 互斥,就是说多个线程不能同时使用同一资源,比如,当线程A使用该资源时,B线程只能等待A释放后才能使用;
    2. 占有等待,就是某线程必须同时拥有N个资源才能完成任务,否则它将占用已经拥有的资源直到拥有他所需的所有资源为止,就好像游戏中,必须两个球都拿到了,才能释放;
    3. 非剥夺,就是说所有线程的优先级都相同,不能在别的线程没有释放资源的情况下,夺走其已占有的资源;
    4. 循环等待,就是没有资源满足的线程无限期地等待。
  • 临界区

    临界区指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待(例如:bounded waiting 等待法),有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用,例如:semaphore。只能被单一线程访问的设备,例如:打印机。

共享存储

共享存储允许两个或多个进程共享一个给定的存储器,是最快的一种IPC。通常使用信号量、记录锁或者互斥量来保证同步。

XSI IPC缺点

  • IPC结果是在系统范围内起作用的,没有引用计数

  • IPC结果在文件系统中没有名字

记录锁

数据库中对于一张表的某行的共享锁与排它锁。

记录锁的功能是:当一个进程正在读或者修改文件的某一个部分时,它可以阻止其他进程修改同一文件区。记录锁其实是字节范围锁,因为它锁定的只是文件中的一个区域,也可能是整个文件。

在设置或释放文件上的锁时,系统按照要求组合或裂开相邻区。

对于修改只读部分的区域,内核为修改区域的内存块制作一个副本,用于写时复制。

锁的隐含继承和释放

  • 当一个进程终止时,它所建立的锁全部释放。

  • 任何时候关闭一个描述符时,则该进程通过这一描述符可以引用的文件上的任何一把锁都被释放

  • 由fork产生的子进程不继承父进程所设置的锁。

  • 在执行exec后,新程序可以继承原执行程序的锁。

建议性锁和强制性锁

  1. 建议性锁是这样规定的:每个使用上锁文件的进程都要检查是否有锁存在,当然还得尊重已有的锁。内核和系统总体上都坚持不使用建议性锁,它们依靠程序员遵守这个规定。(Linux默认是采用建议性锁)
  2. 强制性锁是由内核执行的。当文件被上锁来进行写入操作时,在锁定该文件的进程释放该锁之前,内核会阻止任何对该文件的读或写访问,每次读或写访问都得检查锁是否存在。

例如,我有几个进程(不一定有亲缘关系)都通过fctnl机制来操作文件,这个就叫一致的方法。

但是,如果同时,又有个流氓进程,管它3721,冲上去,open, write。
这时候那几个进程fcntl对这种方式无能为力,这样就叫不一致。文件最后的状态就不定了。

正因为这种锁约束不了其它的访问方式,所以叫建议行锁。强制性锁需要内核支持的,对read, write, open都会检查锁。

socket

套接字接口

套接字接口是一组函数,它们与Unix I/O函数结合起来,用来创建网络应用。

IPC总结_第7张图片

监听描述符与已连接描述符

区分它们可以使我们可以建立并发服务器,如每次一个连接请求到达监听描述符时,可以fork一个新进程,新的进程通过已连接描述符与客户端通信。

IPC总结_第8张图片

你可能感兴趣的:(操作系统,IPC,管道,消息队列,共享内存,socket)