这几天读完了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. PHP中一种sign计算方法

    一言不合上代码......... <?php function getsign($data,$key){ $key=MD5("KEY_".$key."_K" ...

  2. InputStream中通过mark和reset方法重复利用缓存

    通过缓存InputStream可重复利用一个InputStream,但是要缓存一整个InputStream内存压力可能是比较大的.如果第一次读取InputStream是用来判断文件流类型,文件编码等用 ...

  3. 将Object对象转换成Map 属性名和值的形式

    将Java对象转换成Map的键值对形式 代码: package cn.lonelcoud.util; import com.sun.deploy.util.StringUtils; import ja ...

  4. 对于文件File类型中的目录分隔符

    当我们在使用File f=new File(path); 对于这个path来说是一个很痛苦的事情,在不同的系统上面的分隔符号是不一样的 在windows下面的话是一个"\"而在un ...

  5. django新手第一课

    django是基于python的一个web框架,大致结构如下: 在pycharm,python2.7,django1.8,mysql都装好的情况下,现在开始django的初试: 一.基础启动djang ...

  6. Yii2 场景

    下面给大家介绍一下 yii2.0 场景的使用. 现在在 post表里面有 title image content 三个的字段,当我创建一个 post 的时候,我想三个字段全部是必填项,但是你修改的时候 ...

  7. 独立游戏大电影 原名(Indie.Game)

    电影链接 独立游戏大电影 感觉很不错呢!!

  8. Oracle 11g数据库安装和卸载教程

    Oracle11g的安装教程 同时解压缩两个zip文件,生成一个database文件夹,进入到database文件夹,点击setup 去掉安全更新的选项,直接下一步 选择创建和配置数据库,点击下一步 ...

  9. Oracle总结【SQL细节、多表查询、分组查询、分页】

    前言 在之前已经大概了解过Mysql数据库和学过相关的Oracle知识点,但是太久没用过Oracle了,就基本忘了...印象中就只有基本的SQL语句和相关一些概念....写下本博文的原因就是记载着Or ...

  10. 【java学习笔记】文件读写(IO流)

    1.字节流 FileInputStream.FileOutputStream ①FileInputStream import java.io.FileInputStream; public class ...