进程间通信- - -共享内存+消息队列+信号量

本文深入解析了进程间通信(IPC)的三种主要方式:共享内存、消息队列和信号量。详细介绍了共享内存的创建、映射、操作、解除映射和删除流程,以及其在多进程通信中的优势。同时,概述了消息队列和信号量的基本概念及其在进程同步与互斥中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进程间通信

共享内存

共享内存是最快的进程间通信方式,相较于其他进程间通信方式,少了两次内核态与用户态之间的数据拷贝过程

原理及使用过程

  1. 在物理内存中开辟一块内存空间
  2. 将这块内存空间通过页表映射到进程的虚拟地址空间中
  3. 进程可以直接通过进程虚拟地址空间访问到这块物理内存进行操作;若多个进程映射同一块物理内存,就可以实现相互通信;直接通过虚拟地址改变内存中的数据,其他进程的数据也会随之改变
  4. 解除映射关系
  5. 删除共享内存

1. 共享内存的创建

int shmget(key_t key,size_t size,int shmflg);
参数:	key:共享内存在操作系统中的标识符
		size:共享内存的大小
		shmflag:	示例IPC_CREAT|0664
				IPC_CREAT	共享内存若存在则打开,不存在就创建再打开
				IPC_EXCL	与IPC_CREAT同时使用时,若共享内存存在则报错返回
				mode		共享内存的操作权限
		返回值:	正整数---共享内存的操作句柄	失败:-1

2. 共享内存的映射

void *shmat(int shmid,const void *shmaddr,int shmflg);
参数:	shmid	创建共享内存返回的操作句柄
		shmaddr	共享内存在虚拟地址空间中的首地址---通常置NULL
		shmfig	SHM_RDONLY---映射之后,共享内存只读;通常置0-可读可写
		返回值	映射首地址	失败:(void*)-1

3. 共享内存的操作
同常见的内存操作一样,如memcpy/strcpy等

4. 解除映射关系

int shmdt(const void *shmaddr);
参数:	shmaddr	shmat建立映射时返回的映射首地址

5. 删除共享内存

int shmctl(int shmid,int cmd,struct shmid_ds *buf);
参数:	shmid	共享内存操作句柄
		cmd		即将进行的操作-即IPC_RMID	删除共享内存
		buf	用于获取/设置共享内存信息,不关心的话置NULL

共享内存的删除流程:共享内存在使用时会对当前的映射连接数(shm_nattch)进行判断和±操作,在删除的时候,首先会判断当前映射连接数是否为0;若为0则直接删除;否则表示现在还有其他进程正在使用共享内存,不能立即删除,但是会拒绝后续进程的映射连接,等待映射连接数为0时删除

简单使用

//写端
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/shm.h>//注意头文件
#define IPC_KEY 0x12345678

int main()
{
    int shmid = shmget(IPC_KEY, 32, IPC_CREAT|0664);
    if (shmid < 0) {
        perror("shmget error");
        return -1;
    }
    void *shm_start = shmat(shmid, NULL, 0);
    if (shm_start == (void*)-1) {
        perror("shmat error");
        return -1;
    }

    int i = 0;
    while(1) {
        sprintf(shm_start, "%s-%d", "hello world!!", i++);
        sleep(1);
    }

    shmdt(shm_start);//映射首地址
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}
//读端
int main()
{
    int shmid = shmget(IPC_KEY, 32, IPC_CREAT|0664);
    if (shmid < 0) {
        perror("shmget error");
        return -1;
    }
    void *shm_start = shmat(shmid, NULL, 0);
    if (shm_start == (void*)-1) {
        perror("shmat error");
        return -1;
    }

    int i = 0;
    while(1) {
		//在这里循环读取打印缓冲区的内容
        printf("%s\n", shm_start);
        sleep(1);
    }

    shmdt(shm_start);
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}
消息队列

消息队列是操作系统在内核中为用户创建的一个队列;其他进程可以通过访问相同的队列进行通信
消息队列所传输的是有类型的数据块
消息队列的生命周期随内核

信号量

信号量用于实现进程间的同步与互斥
实际上就是内核中的一个计数器,进行资源计数(统计现在有多少资源,用于判断是否能够进行操作)
同步:对临界资源访问的时序和理性
互斥:同一时间对临界资源操作的唯一性

原理:

  1. 互斥原理:只具有0/1计数时,就可以实现互斥
    初始计数为1,表示当前只有一个进程能够获取资源,获取资源之后-1;计数为0,其他进程在等待队列上等待,临界资源被操作完毕之后计数+1,并且唤醒等待队列上的进程

  2. 同步原理:对程序逻辑进行控制(对临界资源合理操作控制)
    通过计数判断当前能否对临界资源进行操作,不能操作(计数<=0),则等待;其他进程操作后计数+1,促使再次判断,唤醒等待的进程

查看ipc的命令
ipcs	查看ipc
ipcs -m	查看共享内存
ipcs -s	查看信号量
ipcs -q	查看消息队列

ipcrm	删除ipc
ipcrm -m shmid	删除共享内存,其他同理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值