首页 > 系统相关 >进程间通信

进程间通信

时间:2023-08-14 20:44:14浏览次数:52  
标签:信号量 IPC int 间通信 进程 共享内存

一、基本概念

什么是进程间通信:
是指两个或多个进程之间需要协同工作、交互数据的过程,因为进程之间是相互独立工作的,为了协同工作就需要进行通信来交互数据
进程间通信的分类:
简单的进程间通信:
信号(携带附加信息)、文件、环境变量、命令行参数等
传统的进程间通信:
管道文件(有名管道、匿名管道)
XSI的进程间通信:
共享内存、消息队列、信号量
网络的进程间通信:
socket套接字

二、传统的进程间通信技术-管道

管道是UNIX系统中最古老的进程间通信方式,古老就意味着所有的系统都支持,早期的管道是半双工,现在有些系统的管道是全双工(假定以半双工来编写代码)
管道是一种特殊的文件,它的数据在管道文件中是流动的,读取后就会自动消失,如果文件中没有数据要读取会阻塞等待
有名管道:
基于有文件名的管道文件的进程间通信,可以是任何进程之间的通信
编程模型:
进程A 进程B
创建管道 ...
打开管道 打开管道
写数据 读数据
关闭管道 关闭管道
删除管道 ...
创建有名管道文件
命令: mkfifo filename
函数:int mkfifo(const char *pathname, mode_t mode);
功能:创建有名管道文件
pathname:文件的路径
mode:文件的权限掩码
匿名管道:没有名字的管道文件
只适合通过fork创建的有血缘关系的进程间通信(父子进程、兄弟进程之间)
int pipe(int pipefd[2]);
功能:创建并打开一个匿名管道文件
pipefd:输出型参数 返回该匿名管道文件的读权限fd和写权限fd
pipefd[0] 用于读管道文件
pipefd[1] 用于写管道文件
编程模型:
父进程 子进程
获取一对fd ...
创建子进程 共享一对fd
关闭读fd[0] 关闭写fd[1]
fd[1]写数据 fd[0]读数据
关闭fd[1] 关闭fd[0]

三、XSI进程间通信

XSI是X/open 公司制定的用于进程间通信的系统(S)接口(I)标准
XSI进程间通信标准都需要借助系统内核完成,需要创建内核对象,内核对象以整数形式返回给用户,相当于文件描述符\文件指针,代表了某个内核对象完成某次进程间通信任务,也叫做IPC标识符
类似文件的创建需要借助文件名一样,IPC标识符的创建也需要借助IPC键值(整数),也跟文件名一样,要确保IPC键值是独一无二的
一般是通过函数生成一个独一无二的IPC键值
key_t ftok(const char *pathname, int proj_id);
功能:生成一个独一无二的IPC键值
pathname:项目路径
proj_id:项目编号
返回值:根据项目路径+项目编号自动计算出IPC键值
注意:计算IPC键值的方式不是根据pathname的字符串内容,而是依靠路径的位置,如果提供了假的路径,不管编号如何,都会得到相同的IPC键值,不正确

共享内存:

基本特点:
两个或多个进程共享同一块由内核负责维护的物理内存,该物理内存是需要与进程的虚拟内存进行映射后使用
优点:不需要进行磁盘读写操作,无需复制操作,是最快的一种IPC机制
缺点:需要考虑通信的同步问题,一般采用信号解决
int shmget(key_t key, size_t size, int shmflg);
功能:创建\获取共享内存
key:IPC键值
size:共享内存的大小,当是获取时此参数无意义写0即可
shmflg:
IPC_CREAT 创建共享内存,已存在时会直接获取
IPC_EXCL 配合CREAT,如果已存在则返回错误
获取时直接给0即可
注意:如果是创建IPC_CREAT,需要在后面额外按位或这段共享内存的读写权限IPC_CREAT|0644
返回值:成功返回该共享内存的IPC标识符,失败返回-1
void *shmat(int shmid, const void shmaddr, int shmflg);
功能:虚拟内存与物理共享内存映射
shmid:IPC标识符
shmaddr:想要映射的虚拟内存首地址,一般给NULL就会自动安排
shmflg:
SHM_RND 只有当shmaddr不是NULL时才有效,当映射的字节数不足一页的整数倍时,会向下取整数倍的页数来映射
SHM_RDONLY 以只读方式映射共享内存
如不需要以上操作,一般给0即可
返回值:成功返回映射的虚拟内存的首地址,失败返回(void
)-1
int shmdt(const void *shmaddr);
功能:取消映射
shmaddr:映射过的虚拟内存首地址
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:删除/控制共享内存
shmid:IPC标识符
cmd:
IPC_STAT 获取共享内存属性信息 buf输出型参数
IPC_SET 修改共享内存的属性 buf输入型参数
IPC_RMID 删除共享内存 buf给NULL即可

    编程模型:
        进程A                       进程B
     创建共享内存                获取共享内存
     映射共享内存                映射共享内存
     写数据到内存并通知         接到通知就读内存数据
     接到通知就读内存数据       写数据到内存并通知
     取消映射                      取消映射
     删除共享内存
消息队列:

基本特点:是一个由内核维护管理的数据链表,通过消息类型来匹配正确后收发数据

    int msgget(key_t key, int msgflg);
    功能:创建\获取消息队列
    key:IPC键值
    msgflg:
        IPC_CREAT   创建消息队列,已存在时会直接获取
        IPC_EXCL    配合CREAT,如果已存在则返回错误
        获取时直接给0即可
        注意:如果是创建IPC_CREAT,需要在后面额外按位或这段消息队列的读写权限IPC_CREAT|0644
    返回值:成功返回该消息队列的IPC标识符,失败返回-1

    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    功能:向消息队列发送消息包
    msqid:IPC标识符
    msgp:要发送的消息包的首地址
        struct msgbuf {
           long mtype;  //第一个成员必须是long类型的消息类型
           char mtext[1];   //根据需要存储数据
       };// 该结构由程序员自己设计
    msgsz:只需要数据的字节数,不包括消息类型
    msgflg:
        阻塞一般写0
        IPC_NOWAIT  当消息队列满时,不等待立即返回
    返回值:成功0 失败-1

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
    功能:从消息队列中接收读取数据
    msqid:IPC标识符
    msgp:消息包内存首地址
    msgsz:数据内存的字节数大小,不包括消息类型,因为不确定对方发送的字节数,因此建议给大一点
    msgtyp:要接收的消息类型
        >0  读取消息类型等于msgtyp的消息
        =0  读取消息队列中的第一条消息
        <0  读取消息队列中的消息类型小于等于abs(msgtyp)的消息如果同时有多个,则读取最小的那一个
    msgflg:
        阻塞等待一般给0即可
        IPC_NOWAIT  如果当时消息类型没有匹配,则不阻塞立即返回
    返回值:成功返回读取到的数据字节数,失败-1

    int msgctl(int msqid, int cmd, struct msqid_ds *buf);
    功能:删除/控制消息队列
    msqid:IPC标识符
    cmd:
        IPC_STAT    获取消息队列属性信息  buf输出型参数 
        IPC_SET     修改消息队列的属性 buf输入型参数
        IPC_RMID    删除消息队列  buf给NULL即可
    编程模型:
        进程A                   进程B
      创建消息队列            获取消息队列
      发送消息msg-a           接收msg-a消息
      接收msg-b消息           发送消息msg-b
      删除消息队列
信号量:

基本特点:由内核维护的一个"全局变量",用于记录进程之间共享资源的数量,限制进程对共享资源的访问
信号量更像是一种数据操作锁,本身是不具备数据交换功能,而是通过控制其他的通信资源(共享内存、消息队列、文件等)来实现进程间通信的协调
1、如果信号量的值>0,说明又可以使用的资源,使用时需要将信号量-1,然后再使用
2、如果信号量的值等于0,说明没有资源可以使用,此时进程会进入休眠,直到信号量的值大于0,进程就会被唤醒,执行步骤1
3、当资源使用完毕后,需要将信号量+1,正在休眠的进程就可以被唤醒执行步骤1
int semget(key_t key, int nsems, int semflg);
功能:创建\获取信号量的IPC标识符
key:IPC键值
nsems:信号量的数量
semflg:
IPC_CREAT 创建信号量,已存在时会直接获取
IPC_EXCL 配合CREAT,如果已存在则返回错误
获取时直接给0即可
注意:如果是创建IPC_CREAT,需要在后面额外按位或这段信号量的读写权限IPC_CREAT|0644
返回值:成功返回该信号量的IPC标识符,失败返回-1

    int semop(int semid, struct sembuf *sops,size_t nsops);
    功能:对某个或某些信号量进行加减操作
    semid:IPC标识符
    sops:
        struct sembuf{
        unsigned short sem_num;  // 信号量的下标
        short          sem_op;   // 
                1   信号量+1
                -1  信号量尝试-1,如果为0则休眠阻塞
                0   等待信号量的值为0,否则阻塞休眠

        short          sem_flg; 
                0           阻塞 
                IPC_NOWAIT  不阻塞
                SEM_UNDO  如果进程终止了没有手动还原信号量+1,系统会自动还原+1  
        };
    nsops:表示sops指针指向多少个连续的结构体,意味着要加减多少个信号量,一般每次只操作一个时写1即可

    int semctl(int semid, int semnum, int cmd, ...);
    功能:删除\控制信号量
    semid:IPC标识符
    semnum:第几个信号量 下标从0开始
    cmd:
        IPC_STAT   获取信号量属性
        IPC_SET    设置信号量属性
        IPC_RMID   删除信号量
        GETALL      获取所有信号量的值
        GETNCNT     获取正在等待减信号量的进程数
        GETVAL     通过返回值获取下标为semnum信号量的值
        GETZCNT    获取正在等待信号量的值为0的进程数
        SETVAL      设置下标为semnum信号量的值
        SETALL      设置所有信号量的值
    ...:
    union semun {
           int              val;    // 用于设置信号量的值
           struct semid_ds *buf;// 用于获取\设置信号量的属性
           unsigned short  *array;  //用于批量设置\获取信号量的值
       };

    使用流程:
        1、创建信号量
        2、设置信号量管理的资源数
        3、减\加信号量
        4、删除信号量

标签:信号量,IPC,int,间通信,进程,共享内存
From: https://www.cnblogs.com/wangqiuji/p/17629678.html

相关文章

  • windows杀死占用端口的进程
    首先按住win+r键,输入cmd,然后按回车进入命令行窗口。1、根据端口号查询进程idnetstat-ano|findstr端口号这里使用的端口是8000,输出结果如下:TCP0.0.0.0:80000.0.0.0:0LISTENING10344结果的最后一列就是占用端口的进程号p_id,这里103......
  • electron渲染进程与主进程之间通信
    首先main.js中通过preload进行预加载脚本__dirname字符串指向当前正在执行的脚本的路径const{app,BrowserWindow}=require('electron');//引入electronconstpath=require('path');letwin;letwindowConfig={width:300,height:600,minWidth:300,we......
  • 8.0 Python 使用进程与线程
    python进程与线程是并发编程的两种常见方式。进程是操作系统中的一个基本概念,表示程序在操作系统中的一次执行过程,拥有独立的地址空间、资源、优先级等属性。线程是进程中的一条执行路径,可以看做是轻量级的进程,与同一个进程中的其他线程共享相同的地址空间和资源。线程和进程都......
  • 8.0 Python 使用进程与线程
    python进程与线程是并发编程的两种常见方式。进程是操作系统中的一个基本概念,表示程序在操作系统中的一次执行过程,拥有独立的地址空间、资源、优先级等属性。线程是进程中的一条执行路径,可以看做是轻量级的进程,与同一个进程中的其他线程共享相同的地址空间和资源。线程和进程都可......
  • 技术分享 | kill掉mysqld_safe进程会影响mysqld进程?
    1、背景公司内部看到一则问题1、kill-9mysqld_safe进程2、systemd检测到mysqld_safe进程不存在后,重新拉起mysqld_safe进程3、mysqld_safe进程启动后,发现mysqld进程也被重启期望:启、停mysqld_safe进程,不会影响mysqld进程2、systemd服务启动2.1、复现问题......
  • 什么是线程?为什么需要线程?线程和进程的区别?
    一.线程是什么?1.1.为什么需要线程    在执行多个任务时,多进程就已经可以实现并发编程的效果了,可是却有一个明显的缺点。 缺点:进程的创建都需要大量的资源(例如:PCB、硬盘资源等),因此开销就变大了;而且创建时需要大量的资源,也是需要更多的时间,因此导致速度变慢了。解决方法......
  • 进程地址空间(虚拟内存)
    进程地址空间,进程虚拟内存的管理。某个进程地址空间的全部区域可以以红黑树+链表的形式存放。内核线程没有mm_struct没有进程地址空间,没有相关的内存描述符,这也是内核线程的真实含义--它们没有用户上下文。当一个进程被调度时,该进程的mm域指向的地址空间被装载到内存,PCB中的acti......
  • 进程管理 & (系统调用 内核同步)
    进程管理在现代操作系统中,进程提供两种虚拟机制,虚拟处理器和虚拟内存PCB描述一个正在执行的程序:打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个或多个执行线程。在2.6以前的版本中,PCB直接放在内核栈的尾端,或者放一个pcb_info间接索引......
  • Linux 共享内存mmap,进程通信
    @TOC前言进程间通信是操作系统中重要的概念之一,使得不同的进程可以相互交换数据和进行协作。其中,共享内存是一种高效的进程间通信机制,而内存映射(mmap)是实现共享内存的一种常见方法。一、存储映射I/O存储映射I/O是一个磁盘文件与存储空间中的一个缓冲区相映射。于是,当从缓冲......
  • 组合式api-子父组件之间通信props和emit
    整体来说和vue2也是比较相似的。使用props传递数据到子组件父组件给定数据。子组件中使用defineProps来接收父组件传递的数据。子组件emit触发事件通知父组件思想和vue2完全一致.....父组件:<scriptsetup>importSonAfrom"@/compon/SonA.vue";import{ref}from......