1.进程间通信的目的
数据传输:一个进程需要将它的数据发送给另一个进程资源共享:多个进程之间共享同样的资源。通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。进程控制:有些进程希望完全控制另一个进程的执行(如 Debug 进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
进程间通信的本质:让不同的进程看到同一份“资源”。
2.进程间通信分类
匿名管道 pipe命名管道
System V 消息队列System V 共享内存System V 信号量
消息队列共享内存信号量互斥量条件变量读写锁
下面只详细介绍匿名管道,命名管道,System V共享内存。
管道
管道是单向通信的,管道是基于文件的,生命周期随进程
管道提供的是面向“流”式通信的,管道提供了访问控制。
3.匿名管道
fd :文件描述符数组 , 其中 fd[0] 表示读端 , fd[1] 表示写端 (可以把0理解成嘴巴(读),把1理解成笔(写))返回值 : 成功返回 0 ,失败返回错误代码
匿名管道原理图
匿名管道是让具有“血缘关系”的进程进行通信的。
创建完匿名管道之后,让父进程关闭"读",让子进程关闭“写”,这样就实现了“一个读,一个写”。
父子进程通过匿名管道进行通信,通信的内容没必要进行刷盘(持久化)。
当管道内没有数据,read会阻塞
当管道被写满,write会阻塞
当写端fd关闭,read返回0
当读端fd关闭,write操作会产生SIGPIPE信号,进而导致write退出
当要写入的数据量大于PIPE_BUF时,linux将不能保证写入的原子性
当要写入的数据量不大于PIPE_BUF时,linux能保证写入的原子性
4.命名管道
匿名管道的限制条件之一是具有“血缘关系”的进程之间进行通信,要想两个不相关的进程能进行通信 ,可以使用FIFO文件,即命名管道。
指明要在哪个路径下创建名为XXX的文件,并指明文件对应的权限,通过调用mkfifo创建该文件。
命名管道原理图
由于是在磁盘上创建有名字文件,这点就是和“匿名管道”的区别。
当然,该文件被加载到内存后,进程可以通过指定路径和指定文件名找到该文件,通过该文件进行进程间通信的内容,也不必刷新到磁盘中。
5.System V共享内存
System V共享内存原理图
System V共享内存进行通信比管道快,是因为数据拷贝次数少。
共享内存有关的函数
ftok
该函数是通过指定路径下的文件名,以及一个整数,系统来创建一个随机的key_t类型的值。
通过调用该函数,让不同的进程能创建出相同的key_t 类型的值(即为让不同进程看到同一份“资源”做铺垫)。
shmget
功能:用来创建共享内存第一个参数是ftok函数创建的随机值,第二个参数是共享内存的大小(建议设置为4096的整数倍),第三个参数如果设置为IPC_CREAT(如果存在,则获取之,如果不存在,则创建),如果设置为IPC_CREAT | IPC_EXCL ,(如果不存在,则创建,如果存在,则出错返回)
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回 -1
shmat
功能:建立共享内存段到进程地址空间之间的映射参数shmid: 共享内存标识shmaddr:指定连接的地址shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1
shmdt
功能:将共享内存段与当前进程之间的映射去掉参数shmaddr: 由shmat所返回的指针返回值:成功返回0;失败返回-1注意:将共享内存段与当前进程脱离不等于删除共享内存段
shmctl
功能:用于控制共享内存参数shmid:由shmget返回的共享内存标识码cmd:将要采取的动作,其中填写 IPC_RMID 用来删除共享内存buf:指向一个保存着共享内存的模式状态和访问权限的数据结构返回值:成功返回0;失败返回-1
其中,struct shmid_ds的结果如下: