这几天读完了UNP v2,对进程间通信与同步的方式有所了解,现对主要的知识点总结如下:

根据出现的历史,先有的管道,FIFO,信号,然后是systemV IPC,再是后来的Poxis IPC,systemV IPC是内核持续性的,而Poxis根据实现不同有的是内核有的是文件系统持续性。

管道:分为管道和FIFO, 管道一般用于父子进程,不能跨进程传输,通过pipe函数调用产生一对文件描述符,父进程fork子进程的时候会复制文件描述符,然后父子进程分别关闭自己不需要的读或写端,如此就可以通信,FIFO可以在文件系统上建立对象,属于一种文件类型(用p标识),可跨进程通信,但是当进程退出时,管道里无法保存数据,不同于管道,FIFO在文件系统上不会被删除。管道一般都是单工的,只能单向通信,管道通信的前提是管道的两端都被打开,不像消息队列等打开一端就可以发送消息。当管道的对端没有打开时,对管道读写都会阻塞, 当读端关闭时,写端写入数据会出发SIGPIPE信号。管道传输的也是字节流,必要时需要制定应用层传输协议来防治粘包。管道出现的较早,在linux系统中大量的使用了管道,例如popen函数的内部实现就是通过管道将调用的命令结果返回给popen调用方。管道的缓冲区大小有限,所以不适合大量的数据通信,当向管道中写入的数据大于缓冲区大小的时候,内核不保证写入的原子性。

消息队列:可以看做是一个消息链表,在某个进程往一个队列中写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。具有内核持续性,也就说一个进程写入消息后可以中止,可让另一个进程在以后某个时候读出该消息。存放的是有边界的消息记录,每个消息含有优先级,POXIS消息队列可以进行notify,在消息到达后通过信号或线程进行消息通知。SystemV消息队列可以指定优先级,优先级高的被优先投递,并支持接收指定优先级的消息。在编写一对多模型的时候不同于管道需要创建多个连接,消息队列只需要创建一个连接,各个进程都可以从其中标识地取出属于自己的消息。缺点就是不能结合select / poll使用,必要时需要用管道转接。新编写的应用程序应该首先考虑使用POXIS消息队列。

互斥锁与条件变量: 可以实现生产者与消费者模型,可以动态分配也可以静态分配,当动态分配并指定共享时可以用在进程间同步,存在的问题是当拥有互斥锁的进程或线程异常终止时可能导致临界区数据不一致。当某个进程阻塞在一个条件变量上的时候,如果调用pthread_exit/pthread_cancel取消线程时,会使该线程再次获得该条件变量的互斥锁,并且线程退出时并不会释放该锁,这样就会造成死锁,解决的办法是使用pthread_cleanup_push/pthread_cleanup_pop来实现清理处理程序的安装和删除。

一般上面两种同步方式是推荐的同步方式,一般使用互斥锁的时候需要用RAII技法封装mutex的创建,销毁,加锁,解锁这四个操作,并用一个Guard对象的构造和析构函数进行lock和unlock操作,Guard是个栈上对象,对象的生命期刚好等于临界区,只使用非递归的mutex,且不使用跨进程的mutex。 使用条件变量时把判断布尔条件和wait()放到while循环中,因为可能会出现虚假唤醒spurious wakeup(参见这里), signal/brodcast操作需要放在mutex之外,否则其他线程无法获得锁,只会徒劳增加线程的调度,条件变量是非常底层的同步原语,很少直接使用,一般都是用它来实现高级的同步措施,如BlockingQueue<T>或CountDownLatch。

读写锁: 可以提高并发度,根据实现的不同,可以分为读优先,写优先。读写锁默认也是线程间的锁,如果需要在进程间锁也需要指定PTHREAD_PROCESS_SHARED 属性。经验告诉我们尽量不要使用读写锁,因为从性能上来说,读写锁并不见得比普通mutex更高效,无论如何reader lock加锁的开销不会比mutex lock小,因为它要更新当前reader的数目,如果临界区很小,锁竞争不激烈,那么mutex往往会更快,并且通常reader lock是可重入的,writer lock是不可重入的,为了防止writer lock饥饿通常会阻塞后来的reader lock,在一些追求低延迟读的场合不适合用读写锁。

记录锁: 可以提供细粒度的锁,并且程序终止时会完成已有锁的清理工作。由内核维护记录锁,分为建议性锁和强制性锁,强制性锁可以阻止非协作进程读一个已被锁住的文件,但这并不能保证数据的一致性。

信号量: 分为有名信号量,基于内存的信号量,systemV信号量,Poxis有名信号量通过一个文件名打开,标识一个内核中文件系统的结构,所以是随内核持久的,可以在进程间或线程间使用,而基于内存的信号量则具有随进程的持续性。

相对于互斥锁有三点不同:

1. 互斥锁必须由给他上锁的线程解锁,信号量没有这种限制;

2. 信号量有一个与之关联的值,它由挂出操作加一,由等待操作减一,那么任何线程都可以挂出一个信号,即使当时没有线程在等待该信号量的值为正数也没关系,但是如果某个线程调用pthread_cond_signal,但是没有任何线程阻塞在pthread_cond_wait调用中,那么相应条件变量的信号将丢失。

3. 各种同步技巧中能够从信号处理程序中安全调用的唯一函数是sem_post函数。互斥锁是为上锁而优化的,条件变量是为等待而优化的,信号量即可用于上锁又可用于等待,因而可能导致更多的开销和更高的复杂性。

SystemV信号量则是计数信号量集,他维护一组信号量,他允许增长或减少信号量的值不只是1,所以相对posix信号量较为复杂。

共享内存区:共享内存区是IPC形式中最快的,一旦这样的内存区映射到共享他的进程的地址空间,这些进程间数据的传递就不需要涉及内核(指不需要通过执行任何进入内核的系统调用,共享内存本身还是在内核中),然而一般需要某种形式的同步。而管道,FIFO,消息队列都需要经由内核传递,所以数据需要四次复制,且都是内核和用户态之间的。

还有一种进程间通信的方式就是socket,其最大的好处就是可以跨主机,具有伸缩性,TCP port由一个进程独占,且操作系统会自动回收,即使程序意外退出,也不会给操作系统留下垃圾,程序重启之后就能比较容易地恢复,而不需要重启操作系统(用跨进程的mutex就有这个风险),对于一些高可用性的系统,快速的故障恢复就导致进程立即重启,这就要求程序只是用操作系统能自动回收的IPC,不使用生命期大于进程的IPC,也不是用无法重建的IPC。还有一个好处,既然port是独占的,那么可以防止程序重复启动,后面那个进程抢不到port,自然就没法初始化了。两个进程通过TCP通信,如果一个崩溃了,操作系统会关闭连接,另一个进程几乎能立刻感知,可以快速faliover。并且TCP协议的一个天生好处就是“可记录,可重现”,用tcpdump等工具就可以调试。并且可以跨语言通信。

muduo库作者陈硕在《Linux多线程服务端编程》中指出“不要使用跨进程的mutex或semaphore”,也不要使用共享内存,因为进程意外终止的话,无法清理资源,特别是无法解锁。另外也不要使用父子进程共享文件描述符的方式来通信(pipe),父进程死了,子进程怎么办?pipe是无法重建的"。

所有的共享方式都各有利弊吧,例如基于内核的有的需要内存拷贝,共享内存快却需要加锁来保障数据的一致性,所以我们应该按需使用,此处不再赘述。

linux同步与通信的更多相关文章

  1. Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式

    Linux就这个范儿 第15章 七种武器  linux 同步IO: sync.fsync与fdatasync   Linux中的内存大页面huge page/large page  David Cut ...

  2. Linux下进程通信的八种方法

    Linux下进程通信的八种方法:管道(pipe),命名管道(FIFO),内存映射(mapped memeory),消息队列(message queue),共享内存(shared memory),信号量 ...

  3. C++同步串口通信

    问题描述:     C++串口通信,设置同步串口通信 问题解决:     (1)打开串口 注:     使用串口需要添加<Windows.h>头文件,打开串口主要是使用CreateFile ...

  4. Windows 下目录及文件向Linux同步

    本文解决的是Windows 下目录及文件向Linux同步的问题,Windows向 Windows同步的请参考:http://www.idcfree.com/article-852-1.html 环境介 ...

  5. linux 同步备份 rsyncd 相关设置

    17:25 2013/10/18------------------ rsync linux 同步备份服务器 配置vi /etc/rsyncd.conf 配置文件 /usr/bin/rsync --d ...

  6. US/OS2之任务同步与通信

    嵌入式系统中的各个任务都是以并发的方式来运行的,并为同一个大的任务服务,它们不可避免地要共同使用一些共享资源,并且在处理一些需要多个任务共同协作来完成的工作时,还需要相互的支持和限制.因此,对于一个完 ...

  7. linux下串口通信与管理

    linux下的串口与windows有一些区别,下面将介绍一下linux下串口通信管理 查看是否支持USB串口: #lsmod | grep usbserial 如果没有信息:sudo apt-get ...

  8. linux下IPC通信

    # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. # 有名管道 (named pipe) : 有名管道也 ...

  9. linux同步windows的时间

    找了很多的资料,都没有windows做时间服务,linux同步windows的时间的,最后自己找了一些软件,终于搞定了,写出来给大家共享,以免大家多走弯路 首先在http://www.meinberg ...

随机推荐

  1. 教我徒弟Android开发入门(二)

    前言: 上一期实现了简单的QQ登录效果,这一期继续对上一期进行扩展 本期的知识点: Toast弹窗,三种方法实现按钮的点击事件监听 正文:   Toast弹窗其实很简单,在Android Studio ...

  2. bzoj 2120 带修改莫队

    2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 7340  Solved: 2982[Submit][Status][Discuss] ...

  3. java1 - 环境与简介

    一.阅读 JAVA历史 回答以下问题: JDK 是什么? JRE 是什么? java 有那三大平台? java 开发工具有那些? java 可以在那些系统上面做开发? java 工程师可以做什么? 二 ...

  4. 在SpringBoot中添加Logback日志处理

    前言 SpringBoot项目中在官方文档中说明,默认已经依赖了一些日志框架.而其中推荐使用的就是Logback,所以这一次我将在我的模版中加入Logback日志的配置,说明一下,SpringBoot ...

  5. SQL Server 死锁的告警监控

    今天这篇文章总结一下如何监控SQL Server的死锁,其实以前写过MS SQL 监控错误日志的告警信息,这篇文章着重介绍如何监控数据库的死锁,当然这篇文章不分析死锁产生的原因.以及如何解决死锁.死锁 ...

  6. 基于全志H3芯片的ARM开发环境搭建

    基于全志H3芯片的ARM开发环境搭建 最近买了个友善之臂的NanoPi M1板子,又在网上申请了个NanoPi NEO板子,这两个都是基于全志H3芯片的Crotex-A7四核ARM开发板,两个板子可以 ...

  7. ubuntu 14.04 分辨率调整 -- xrandr命令

    问题描述: 自己在安装ubuntu-kylin 14.04 TLS系统成功后,在调整分辨率的时候(系统设置--显示)发现分辨率的选项只有1024x768以及800x600两个选项,而台式机的外接显示屏 ...

  8. 嵌入式Linux引导过程之1.5——从BootRom到Xloader

    在开始看Xloader_Entry的代码之前,我想先总结一下从芯片上电到开始运行Xloader的代码的过程,这是我目前理解的一个过程,可能有所出入,待以后继续完善. 当 系统上电之后,首先会将PC寄存 ...

  9. discuz 更换域名 导致qq登录不能用的问题

    今天论坛换了域名,导致qq登录不能用.于是各种百度,终于找到了解决方案,特此记录一下 解决方法:1,首先清空你站点的id和key,并且设置为未注册云平台: 2,找一个新域名(未开过云平台的就可),如果 ...

  10. ip2long的用法

    ip2long:将IPv4的ip地址(以小数点分隔形式)转换为int Description int ip2long ( string ip_address ) 如果ip地址非法,返回FALSE(PH ...