一、背景

进程间相互独立,内部变量,别的进程不可见
由内核提供一份公共资源,让多个进程可以看见

条件

  1. 独立性
  2. 为了相互通信,有共享资源
  3. 共享由操作系统内核实现

二、匿名管道

前一个进程的标准输出作为后一个进程的标准输入
1.本质

内核提供的一段内存(队列),通过内存借助这段内存,完成进程间通信。然后将管道这段内存抽象成文件。通过访问文件描述符的形式,来读写这块内存中的数据。

2.特点

1.只适用于具有亲缘关系的进程
2.单向通信,半双工
3.面向字节流
4.内置同步互斥机制

互斥:多个进程一起读,读到完整数据或者读不到数据
同步:管道为空,读阻塞;管道满了,写阻塞

5.生命周期随内存

所有引用这个管道的进程都销毁,管道才释放。真正释放的只是管道在内核中对应的这段内存,这个内存才是管道的本质

3.相关函数函数
pipe(创建一个匿名管道)

#include <unostd.h> int pipe (int fd[2]);
//参数:fd:文件描述符数组;fd[0]:读端;fd[1]:写端
//返回值:创建成功返回0;创建失败返回错误码


eg:从输入读取数据,写入管道,读取管道,写到输出(默认阻塞式等待)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int main() {  int fd[2];char buf[1024];int len;if (pipe(fd) == -1){      perror("make pipe");return 1;}//read from stdinwhile(fgets(buf , 1024 , stdin)) {len = strlen(buf);//write into pipeif (write (fd[1] , buf , len) != len) {perror("write tp pipe");break;}memset (buf , 0x00 , sizeof(buf));//read from pipeif ((len = read(fd[0] , buf , 1024)) == -1){perror("read from pipe");break;}//write to stdoutif (write(1,buf,len) != len) {perror("write to stdout");break;}}return 0;
}

三、命名管道 != 命名管道文件

1.本质
同匿名管道

内核提供的一段内存(队列),通过内存借助这段内存,完成进程间通信。然后将管道这段内存抽象成文件。通过访问文件描述符的形式,来读写这块内存中的数据。

2.特点
除第一条以外,其余与匿名管道相同

1.适用于任何进程
2.单向通信,半双工
3.面向字节流
4.内置同步互斥机制

互斥:多个进程一起读,读到完整数据或者读不到数据
同步:管道为空,读阻塞;管道满了,写阻塞

5.生命周期随内存

所有引用这个管道的进程都销毁,管道才释放。真正释放的只是管道在内核中对应的这段内存,这个内存才是管道的本质

3.相关函数函数
同系统调用。
创建命名管道

//命名管道可以从命令行上创建,命令行方法是使用命令:
$ mkfifo filename
//创建管道文件,(p开头)//命名管道也可以从程序里创建,相关函数有:
int mkfifo (const char* filename , mode_t mode);
//参数:(* filename)文件名;(mode)权限
int main() {mkfifo("p2" , 0644);return 0;
}

匿名管道与命名管道的区别

匿名管道由pipe函数创建并打开
命名管道由mkfifo函数创建,打开用open
FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在于创建与打开方式不同,除此之外,均一致


四、消息队列

1.本质

本质是内核中的一个链表,因此在访问消队列的时候,按照节点为单元,访问数据的读,写

2.特点

1.适用于任何进程
2.全双工,半通信
3.面向数据报

按照节点为单位,一个一个读,一个一个写

4.内置同步互斥机制
5.生命周期随内核

进程没了,消息队列还在,msgctl , IPC rm指令手动删除,或者重启(一直存在到显示删除/系统重启)

3.相关函数函数

//IPC(进程间通信)对象数据结构
//内核为每个IPC对象维护一个数据结构(消息队列,信号量,共享内存都有该结构)
//类型:业务上类型(用途)
struct ipc_perm    {  //√      key_t          __key;       /* Key supplied to msgget(2) */   //IPCK,多个进程找到同一个消息队列 uid_t          uid;         /* Effective UID of owner */    gid_t          gid;         /* Effective GID of owner */    uid_t          cuid;        /* Effective UID of creator */    gid_t          cgid;        /* Effective GID of creator */  //√  unsigned short mode;        /* Permissions */    //IPC对象权限unsigned short __seq;       /* Sequence number */
};   
//消息队列结构
struct msqid_ds
{  //√  struct ipc_perm msg_perm;     /* Ownership and permissions 各类IPC对象所共有的数据结构*/  //ipc_perm//√  struct msg *msg_first;     /* first message on queue,unused */     struct msg *msg_last;     /* last message in queue,unused */     //链表__kernel_time_t          msg_stime;    /* Time of last msgsnd(2) */  __kernel_time_t          msg_rtime;    /* Time of last msgrcv(2) */  __kernel_time_t          msg_ctime;    /* Time of last change */  unsigned long   __msg_lcbytes;    /* Reuse junk fields for 32 bit */unsigned long   __msg_lqbytes;    /* ditto */unsigned short   __msg_cbytes;    /* Current number of bytes in queue (nonstandard) 消息队列中当前所保存的字节数 */  unsigned short   __msg_qnum;    /* Current number of messages in queue 消息队列中当前所保存的消息数 */unsigned short   __msg_qbytes;    /* Maximum number of bytes allowed in queue 消息队列所允许的最大字节数 */__kernel_ipc_pid_t           msg_lspid;    /* PID of last msgsnd(2) 最后一个发送数据的进程号*/  __kernel_ipc_pid_t           msg_lrpid;    /* PID of last msgrcv(2) 最后一个接受的进程号*/
};

注:ftok构造IPCK
消息队列函数

由于消息队列API,使用起来相对麻烦
1.我们把这些API封装起来
2.基于已经封装的代码,实现相应程序

$ ipcs -q  ;
//查看有哪些消息队列
$ ipcrm -q mspid
//手动删除消息队列

[msgget]创建(用来访问和创建一个消息队列)

int msgget(key_t, key, int msgflg);//参数:(key),消息队列名字;(msgflg),权限标志,表消息队列的访问权限,与文件的访问权限一样。IPC_CREAT,不存在就创建,存在就失败;IPC_EVCL,存在打开失败
//返回值:成功返回消息队列标识码;失败返回-1

[msgctl]销毁(控制函数)

int msgctl(int msgid, int cmd struct msgid_ds *buf);//参数:(msgid),msgget函数返回的消息队列标识码;(cmd),将要采取的动作(有3个值);(*buf),指向msgid_ds的结构体指针,随cmd变化
//•IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
//•IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
//•IPC_RMID:删除消息队列//返回值:成功返回0;失败返回-1

[msgsnd]添加

int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);
//参数:(msgid),由msgget函数返回的消息队列标识符;
//     (*msgp),是一个指针,指向准备发送的消息;
//     (msgsz),是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型;
//     (msgflg),控制着当前消息队列满或者达到系统上限时将要发生的事情;msgflg = IPC_NOWAIT表示,消息队列满的时候不等待,直接返回EAGAIN错误
//返回值:成功返回0;失败返回-1

注:

1.消息队列在两方面受到制约①它必须小于系统规定的上限值②它必须以一个long int长整型开始,接受者函数将利用这个长整型确定消息的类型
2.消息结构参考形式:
struct msgbuf {long mtype;//数据类型(业务上类型)char mtext[1];
}

[msgrcv]接收

int msgrcv(int msgid, void *msgp, size_t msgsz, long msgtype, int msgflg);
//参数:(msgid),从哪个消息队列中读取,由msgget函数返回的消息队列标识码;
//     (*msgp),指针,指向准备接收的消息;
//     (msgsz),msgp指向消息的长度,不含保存消息类型的那个long int长整型;
//     (msgtype),取哪一种类型,实现接收优先级的简单形式;
//     (msgflg),控制着队列中没有相应类型的消息可供接收时将要发生的事。
//返回值:成功返回实际放到接收缓冲区里的字符个数,失败返回-1

注:

msgtype = 0;//返回队列第一条消息
msgtype > 0;//返回队列第一条类型等于msgtype的消息
msgtype < 0;//返回队列第一条类型小于等于msgtype绝对值的消息,并且是满足条件的消息类型最小的消息
msgflg = IPC_NOWAIT;//队列没有可读消息不等待,直接返回ENOMSG消息
msgflg = MSG_NOERROR;//消息大小超过msgsz时被截断
msgtype > 0 且 msgflg = MSG_EXCEPT;//接收类型不等于msgtype的第一条消息

五、共享内存

1.本质

同一块物理内存通过页表分别映射到不同进程的虚拟地址空间中,从而导致说,第一个内存修改变量,物理内存发生变化,第二个内存再去读取,就能感知到变量的改变

2.特点

1.适用于任何进程

只要构造相同IPCK,传相同PATHNAME以及相同PROJ_ID,自然可以得到相同的IPCK,打同一个共享内存(同消息队列)

2.双向通信(既能读,又能写)
3.没有同步互斥机制
4.不存在面向字节流和面向数据报的概念,只是一块内存,可以随意的读写数据,随机访问
5.生命周期随内核(没有手动销毁,一直存在到系统重启)

3.相关函数
[shmget]创建共享内存

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int   shmget(key_t key, size_t size, int flag); //参数:(key),共享内存的标识符;(size),共享内存大小,PAGE_SIZE向上取整,4k的整数倍;(flag),权限
//返回值:成功返回共享内存标识符;失败返回-1

[shmat]"malloc"将共享内存段连接到进程地址空间

void* shmat(int shmid,  const void *shmaddr, int shmflg);
//参数:(shmid),共享内存标识;(shmaddr),指定连接的地址;(shmflg),可能取SHM_RND或者SHM_RDONLY
//返回值:成功返回一个指向共享内存第一个节的指针;失败返回-1

[shmdt]"free"将共享内存段与当前进程脱离

int   shmdt(char *shmaddr);
//参数:(shmaddr),由shmat返回的指针
//返回值:成功返回0;失败返回-1
//注:将共享内存段与当前进程脱离不等于删除共享内存段

[shmctl]"destroy"用于控制共享内存

int   shmctl(int shmid, int cmd, struct shmid_ds *buf);
//参数:(shmid),由shmget返回的共享内存表示符;(cmd),将要采取的动作(三个可取值);
//•IPC_STAT:sh把mid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
//•IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
//•IPC_RMID:删除共享内存
//(buf),指向一个保存着共享内存的模式状态和访问权限的数据结构
//返回值:成功返回0;失败返回-1

4.优势

[共享内存效率极高]因为访问共享内存与普通内存没有任何差别,而要进行管道/消息队列的话,涉及到反复地把数据从内核拷贝到用户又从用户拷贝到内存,反复拷贝,开销积少成多


六、信号量

1.本质

信号量就是一个计数器。
信号量并不是让进程间能够直接的发送字符串数据,而是通过自身计数器的性质,来完成进程之间的同步和互斥。
二元信号量(类似于互斥锁)
计数器(可用资源剩余个数)+ 等待队列
并没有直接给进程间通信传递字符串信息,但是可以用于进程之间的同步与互斥

2.特点

1.适用于任何进程
2.生命周期随内核

3.同步与互斥
互斥

由于进程要共享资源,有些资源需要互斥使用,因此各进程间的竞争关系为互斥
系统中某些资源一次只允许一个进程使用,这样的资源称为临界资源或互斥资源
同步
为了完成一项任务,多个进程的先后顺序叫做同步

4.信号量,P,V
互斥:P、V 在同一个进程
同步:P、V 不在一个进程

P(申请资源) 信号量 -1
V(释放资源) 信号量 +1
信号量值含义:
S > 0:S表示可用资源个数
S = 0:表示无可用资源,无等待进程
S < 0:|S|表示等待队列中进程个数

注:system版本信号量,S 不可能 < 0

4.相关函数函数
[semget]创建/访问信号量
一个信号量数组,可以通过数组下标访问到具体

int semget(key_t key, int nsems, int semflg);//参数:key,信号集的名字;nsems,信号集中信号量的个数;semflg,权限
//返回值:成功返回信号集标识码;失败返回-1

[semctl]控制信号量集(销毁)

int semctl(int semid, int semnum, int cmd, ...);//参数:semid,信号量集标识符;semnum,信号量集数组上的下标,表示某一个信号量;cmd,将要采取的动作;最后一个参数根据命令不同而不同
//返回值:成功返回0;失败返回-1

IPC_STAT,从信号量集上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中;
IPC_SET,设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值;
IPC_RMID,从内核中删除信号量集合(销毁);
SETVAL,用联合体中val成员的值设置信号量集合中单个信号量的值(初始化);
GETVAL,返回信号量集合内单个信号量的值

[semop]创建和访问一个信号量集

int semop(int semid, struct sembuf *sops, unsigned nsops);//参数:semid,信号量集标识符 ; sops,指向进行操作的信号量集结构体数组的首地址 ; nsops,进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作//返回值:成功返回0;失败返回-1
struct sembuf {short semnum; /*信号量集合中的信号量编号,0代表第1个信号量*/short val;/*若val>0进行V操作信号量值加val,表示进程释放控制的资源 *//*若val<0进行P操作信号量值减val,若(semval-val)<0(semval为该信号量值),则调用进程阻塞,直到资源可用;若设置IPC_NOWAIT不会睡眠,进程直接返回EAGAIN错误*/ /*若val==0时阻塞等待信号量为0,调用进程进入睡眠状态,直到信号值为0;若设置IPC_NOWAIT,进程不会睡眠,直接返回EAGAIN错误*/short flag;  /*0 设置信号量的默认操作*//*IPC_NOWAIT设置信号量操作不等待*//*SEM_UNDO 选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值*/}; 

(Linux)进程间通信相关推荐

  1. linux进程间通信:POSIX 共享内存

    文章目录 思维导图 通信原理 优势 POSIX 共享内存 编程接口 编程案例 思维导图 之前学习过sysemV 的共享内存的实现及使用原理,参考linux进程间通信:system V 共享内存 POS ...

  2. linux进程间通信:POSIX 消息队列 ----异步通信

    在上一篇中linux进程间通信:POSIX 消息队列我们知道消息队列中在消息个数达到了队列所能承载的上限,就会发生消息的写阻塞. 阻塞式的通信影响系统效率,进程之间在通信收到阻塞时并不能去做其他事情, ...

  3. linux进程间通信:POSIX 消息队列

    文章目录 基本介绍 相关编程接口 编程实例 消息队列通信实例 消息队列属性设置实例 基本介绍 关于消息队列的基本介绍,前面在学习system V的消息队列时已经有过了解,linux进程间通信:syst ...

  4. linux进程间通信:system V 信号量 生产者和消费者模型编程案例

    生产者和消费者模型: 有若干个缓冲区,生产者不断向里填数据,消费者不断从中取数据 两者不冲突的前提: 缓冲区有若干个,且是固定大小,生产者和消费者各有若干个 生产者向缓冲区中填数据前需要判断缓冲区是否 ...

  5. Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存

    Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...

  6. Linux进程间通信(二):信号集函数 sigemptyset()、sigprocmask()、sigpending()、sigsuspend()...

    我们已经知道,我们可以通过信号来终止进程,也可以通过信号来在进程间进行通信,程序也可以通过指定信号的关联处理函数来改变信号的默认处理方式,也可以屏蔽某些信号,使其不能传递给进程.那么我们应该如何设定我 ...

  7. 20155301 滕树晨linux基础——linux进程间通信(IPC)机制总结

    20155301 滕树晨linux基础--linux进程间通信(IPC)机制总结 共享内存 共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在 ...

  8. Linux 进程间通信

    引言 进程通信的目的: 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一 ...

  9. Linux进程间通信中的文件和文件锁

    Linux进程间通信中的文件和文件锁 来源:穷佐罗的Linux书 前言 使用文件进行进程间通信应该是最先学会的一种IPC方式.任何编程语言中,文件IO都是很重要的知识,所以使用文件进行进程间通信就成了 ...

  10. linux 进程间通信 dbus-glib【实例】详解四(上) C库 dbus-glib 使用(附代码)(编写接口描述文件.xml,dbus-binding-tool工具生成绑定文件)(列集散集函数)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

最新文章

  1. 旷视张祥雨:高效轻量级深度模型的研究和实践 | AI ProCon 2019
  2. 谈谈 Java 中自定义注解及使用场景
  3. leetcode 98. 验证二叉搜索树 递归遍历左右子树和中序遍历 c语言解法
  4. 【三分钟刷一题力扣】移除元素
  5. ASP.NET Core Blazor Webassembly 之 数据绑定
  6. Python工作笔记-仿大佬的list赋值
  7. 工程师的基本功是什么?如何练习?听美团技术大咖怎么说
  8. 程序员很忙吗_当一个程序员一天被打扰 10 次,后果很惊人!
  9. redis与memcached区别
  10. 【SQL注入-02】SQL注入点的简单判断
  11. Windows下制作DOS启动U盘的方法
  12. java基础语法(三)--运算符、控制语句
  13. stm32 无线打印机服务器,STM32开发的蓝牙热敏打印机
  14. Excel如何将英文前的中文全部提取出来
  15. Java迭代器和lambda的区别,Java使用Lambda表达式遍历Iterator迭代器
  16. elasticsearch 基础 —— Jion父子关系
  17. matlab三元一次方程组的解包含未知数,用matlab解三元一次方程组_matlab解高阶方程_matlab二分法求方程的近似解...
  18. deno计算机语言什么意思,一篇文章告诉你什么是Deno!
  19. PyQt(Python+Qt)学习随笔:纯文本编辑器QPlainTextEdit功能详解
  20. 带空格直角三角形图案的输出-c++

热门文章

  1. python爬取电影票房前50_Python3爬取起猫眼电影实时票房信息,解决文字反爬~~~附源代码...
  2. JavaScript对输入的用户名密码等进行判断
  3. leetcode 19. 删除链表的倒数第 N 个结点(c++)
  4. 股票macd计算公式php,【图】日周MACD同图(日线公式)_选股公式,股票,炒股,股票软件,股票公式_指标公式分享交流论坛_理想论坛 - 股票论坛...
  5. 高中计算机操作题frontpage步骤,计算机一级Frontpage操作试题
  6. xbox one x驱动_Xbox One,Xbox One S和Xbox One X有什么区别?
  7. java脱机是什么意思_java获取本地打印机,以及判断打印机是否脱机状态
  8. 需求与商业模式创新-需求9-原型
  9. 讯飞机器翻译质量评估挑战赛Baseline(PaddlePaddle)
  10. Ubuntu-18.04安装