Linux---共享内存

1.ipcs命令

IPC机制是一个让人烦恼的问题:编写错误的程序或因为某些原因而执行失败的程序将把它的IPC资源(如消息队列中的数据)遗留在系统里,并且这些资源在程序结束后很长时间让然在系统中游荡,这导致对程序的新调用执行失败,因为程序期望以一个干净的系统来启动,但事实上却发现一些遗留的资源。

状态命令ipcs和删除命令(ipcrm)提供了一种检查和清理IPC机制的方法

ipcs -s只查看信号量

ipcs -m只查看共享

ipcs -q只查看消息队列

ipcrm删除操作

例如:ipcrm -s semid;

重启一下,信号量等自动删除

2.共享内存介绍

共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理地址上申请一块空间,多个进程可以将其映射到自己的虚拟地址空间中。所以进程都可以访问共享内存中的地址,就好像它们是由malloc分配的一样。如果某个进程向共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。

但是由于它并未提供同步机制,所以我们通常需要用其他的机制来同步对共享内存的访问。

5.共享内存函数介绍
1)shmget

int shmget(key_t key, size_t size, int shmflg);shmget()用于创建或者获取共享内存shmget()成功返回共享内存的 ID, 失败返回-1key: 不同的进程使用相同的 key 值可以获取到同一个共享内存,(这里的值和信号量的值一样也没有关系,因为类型不一样;)size: 创建共享内存时,指定要申请的共享内存空间大小shmflg: IPC_CREAT IPC_EXCL

2)shmat

void* shmat(int shmid, const void *shmaddr, int shmflg);shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上shmat()成功返回返回共享内存的首地址,失败返回 NULL(像malloc一样给共享空间的起始地址),看帮助手册失败返回的是-1;shmaddr:一般给 NULL,由系统自动选择映射的虚拟地址空间shmflg: 一般给 0(给0就代表的可读可写), 可以给 SHM_RDONLY 为只读模式,其他的为读写


3)shmdt

int shmdt(const void *shmaddr);shmdt()断开当前进程的 shmaddr 指向的共享内存映射shmdt()成功返回 0, 失败返回-1//为什么不是删除共享内存而是断开共享内存呢?因为你不使用了,别的进程可能还在使用这块共享内存;//删除共享内存用shmctl,就是对共享内存做控制,那么可以设置,也可以删除,如下的函数;

4)shmctl

int shmctl(int shmid, int cmd, struct shmid_ds *buf);shmctl()控制共享内存shmctl()成功返回 0,失败返回-1cmd: IPC_RMID//删除的时候如果还有人在使用共享内存,这个函数就会延迟删除,等到最后一个进程断开链接它才会删除共享内存.//第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。

3.共享内存的使用

代码演示例1:


进程a向共享内存写入数据(写一次hello),进程b从共享内存读取数据(读取hello)并显示.
main.c写入数据
test.c读取数据

//main.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/shm.h>
#include<assert.h>
#include<string.h>
int main()
{int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//创建一块动态内存assert(shmid!=-1);char *s=(char*)shmat(shmid,NULL,0);//一般给0,0表示//将申请的共享内存的物理地址映射到当前进程的虚拟空间上//assert(s!=NULL);if(s==(char*)-1){exit(1);}strcpy(s,"hello");//把hello写到s里,即共享内存里写的就是helloshmdt(s);//断开当前进程的映射
}

//test.c

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/shm.h>
#include<assert.h>
#include<string.h>
int main()
{int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//创建一块动态内存assert(shmid!=-1);char *s=(char*)shmat(shmid,NULL,0);//一般给0,0表示//将申请的共享内存的物理地址映射到当前进程的虚拟空间上//assert(s!=NULL);if(s==(char*)-1){exit(1);}printf("%s",s);//打印获取的地址里面的内容shmdt(s);//断开当前进程的映射shmctl(shmid,IPC_RMID,NULL);//删除共享内存exit(0);
}

结果:

代码演示例2:

进程 a 从键盘循环获取数据并拷贝到共享内存中,进程 b 从共享内存中获取并打印数据。要求进程 a 输入一次,进程 b 输出一次,进程 a 不输入,进程 b 也不输出。

我们要了解进程管理的P V操作:

P:代表对资源的申请(-1)

V:代表对资源的释放(+1)

代码如下:

//main.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/shm.h>
#include<assert.h>
#include<string.h>
int main()
{int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//创建一块动态内存assert(shmid!=-1);char *s=(char*)shmat(shmid,NULL,0);//一般给0,0表示//将申请的共享内存的物理地址映射到当前进程的虚拟空间上//assert(s!=NULL);if(s==(char*)-1){exit(1);}//strcpy(s,"hello");//把hello写到s里,即共享内存里写的就是hellowhile(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);strcpy(s,buff);//把buff里面的东西拷贝到s里面if(strncmp(buff,"end",3)==0){break;}//输入end表示退出}shmdt(s);//断开当前进程的映射exit(0);}//test.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/shm.h>
#include<assert.h>
#include<string.h>
int main()
{int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//创建一块动态内存assert(shmid!=-1);char *s=(char*)shmat(shmid,NULL,0);//一般给0,0表示//将申请的共享内存的物理地址映射到当前进程的虚拟空间上//assert(s!=NULL);if(s==(char*)-1){exit(1);}while(1){if(strncmp(s,"end",3)==0){break;}printf("read:%s\n",s);//打印获取的地址里面的内容sleep(1);}shmdt(s);//断开当前进程的映射shmctl(shmid,IPC_RMID,NULL);//删除共享内存exit(0);
}

  

这样会出问题, test.c如果没有sleep(1)就会疯狂的打印,所以共享内存必须结合信号量

正确做法:

遇到这类问题我们主要思考三个点:

1.信号量的个数

2.信号量的初始值

3.P V操作

//sem.h
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/sem.h>#define SEM1 0
#define SEM2 1
#define SEM_MAX 2
union semun
{int val;
};
void sem_init();
void sem_p(int index);
void sem_v(int index);
void sem_destory();//sem.c
#include"sem.h"static int semid=-1;
void sem_init()
{semid=semget((key_t)1234,SEM_MAX,IPC_CREAT|IPC_EXCL|0600);//全新创建if(semid==-1){semid=semget((key_t)1234,SEM_MAX,0600);//失败了就再获取一下if(semid==-1){printf("sem failed!\n");//真的失败了return;}}else{union semun a;int arr[SEM_MAX]={1,0};for(int i=0;i<SEM_MAX;i++){a.val=arr[i];if(semctl(semid,i,SETVAL,a)==-1){printf("semctl setval failed!\n");}}}
}void sem_p(int index)
{if(index<0||index>=SEM_MAX){return;}struct sembuf a;a.sem_num=index;a.sem_op=-1;a.sem_flg=SEM_UNDO;if(semop(semid,&a,1)==-1){printf("semop p error!\n");}
}void sem_v(int index)
{if(index<0||index>=SEM_MAX){return;}struct sembuf a;a.sem_num=index;a.sem_op=1;a.sem_flg=SEM_UNDO;if(semop(semid,&a,1)==-1){printf("semop v error!\n");}
}void sem_destory()
{if(semctl(semid,0,IPC_RMID)==-1){printf("destory error!\n");}
}//main.c
#include"sem.h"
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/shm.h>
#include<assert.h>
#include<string.h>
int main()
{int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//创建一块动态内存assert(shmid!=-1);char *s=(char*)shmat(shmid,NULL,0);//一般给0,0表示//将申请的共享内存的物理地址映射到当前进程的虚拟空间上//assert(s!=NULL);if(s==(char*)-1){exit(1);}//strcpy(s,"hello");//把hello写到s里,即共享内存里写的就是hellosem_init();while(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);sem_p(SEM1);strcpy(s,buff);//把buff里面的东西拷贝到s里面sem_v(SEM2);if(strncmp(buff,"end",3)==0){break;}//输入end表示退出}shmdt(s);//断开当前进程的映射exit(0);}//test.c
include"sem.h"
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/shm.h>
#include<assert.h>
#include<string.h>
int main()
{int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);//创建一块动态内存assert(shmid!=-1);char *s=(char*)shmat(shmid,NULL,0);//一般给0,0表示//将申请的共享内存的物理地址映射到当前进程的虚拟空间上//assert(s!=NULL);if(s==(char*)-1){exit(1);}sem_init();while(1){sem_p(SEM2);if(strncmp(s,"end",3)==0){break;}	printf("read:%s\n",s);//打印获取的地址里面的内容sem_v(SEM1);//sleep(1);}shmdt(s);//断开当前进程的映射sem_destory();shmctl(shmid,IPC_RMID,NULL);//删除共享内存exit(0);
}

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/26674.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RAG 阿里云

RAG-阿里云Spring AI Alibaba官网官网 RAG-阿里云Spring AI Alibaba官网官网 AI应用跑起来&#xff0c;取消一下航班的操作666

M4 Mac mini运行DeepSeek-R1模型

前言 最近DeepSeek大模型很火&#xff0c;实际工作中也有使用&#xff0c;很多人觉得需要很好的显卡才能跑起来&#xff0c;至少显存需要很高&#xff0c;但实际上一般的核显机器也能跑起来&#xff0c;只不过内存要求要大&#xff0c;对于个人而言&#xff0c;实际上Mac M芯片…

【Cadence射频仿真学习笔记】2.4GHz低噪放LNA仿真设计

课程分为3个部分&#xff0c; 一、LNA结构与噪声优化方法 噪声优化的方法是&#xff1a;限定功耗的噪声和功率同时匹配噪声匹配和功率匹配一般不会同时达到&#xff0c; 对于PCSNIM结构的噪声分析&#xff0c;我们只需要了解与哪些参数有关优化思路是&#xff1a;1.信号源阻抗…

机器学习:线性回归,梯度下降,多元线性回归

线性回归模型 (Linear Regression Model) 梯度下降算法 (Gradient Descent Algorithm) 的数学公式 多元线性回归&#xff08;Multiple Linear Regression&#xff09;

C++22——哈希

目录 1.unordered_map的文档介绍 2.unordered_set的文档介绍 3.底层结构 3.1哈希的概念 3.2哈希冲突 3.3哈希函数 3.4哈希冲突解决 3.4.1闭散列 3.4.2开散列 1.unordered_map的文档介绍 unordered_map在线文档说明 unordered_map是存储<key&#xff0c;value>键值…

Docker 搭建 Gitlab 服务器 (完整详细版)

参考 Docker 搭建 Gitlab 服务器 (完整详细版)_docker gitlab-CSDN博客 Docker 安装 (完整详细版)_docker安装-CSDN博客 Docker 日常命令大全(完整详细版)_docker命令-CSDN博客 1、Gitlab镜像 # 查找Gitlab镜像 docker search gitlab # 拉取Gitlab镜像 docker pull gitlab/g…

如何杀死僵尸进程?没有那个进程?

在题主跑代码的时候遇到了这样一种很奇怪的问题&#xff1a; 可以看到显卡0没有跑任何程序但是还是被占据着大量显存&#xff0c;这种进程称为“僵尸进程”&#xff0c;并且当我想kill它的时候&#xff0c;出现下面这种情况&#xff1a; 查过各种资料&#xff0c;最后我的解决…

从0开始的IMX6ULL学习篇——裸机篇之分析粗略IMX6ULL与架构

目录 简单的说一下Cortex-A7架构 讨论ARMv7a-cortex系列的运行模式 寄存器 后言 让我们到NXP的官网上扫一眼。 i.MX 6ULL应用处理器_Arm Cortex-A7单核&#xff0c;频率为900 MHz | NXP 半导体 我们先看CPU Platform&#xff0c;这个是我们的核心。 这里我们的芯片是基于Ar…

从UNIX到Linux:操作系统进化史与开源革命

从UNIX到Linux&#xff1a;操作系统进化史与开源革命 一、操作系统&#xff1a;数字世界的基石 1.1 什么是操作系统&#xff1f; 操作系统&#xff08;OS&#xff09;是计算机系统的核心管理者&#xff0c;承担着三大核心使命&#xff1a; 硬件指挥官&#xff1a;直接管理C…

风控算法技术图谱和学习路径

风控算法技术图谱和学习路径可以从以下几个方面进行详细阐述: 一、风控算法技术图谱 基础知识与理论框架 风控算法技术的核心在于数据处理、特征工程、模型构建及优化。基础知识包括统计学、机器学习、深度学习、图算法等。例如,基于Python的智能风控书籍详细介绍了信贷风控…

Word 插入图片会到文字底下解决方案

一、现象描述 正常情况下&#xff0c;我们插入图片都是这样的。 但有时突然会这样&#xff0c;插入的图片陷于文字底部。 二、网上解决方案 网上有教程说&#xff0c;修改图片布局选项&#xff0c;从嵌入型改成上下型环绕。改完之后确实有用&#xff0c;但是需要手动拖动图片…

NO.22十六届蓝桥杯备战|一维数组|七道练习|冒泡排序(C++)

B2093 查找特定的值 - 洛谷 题⽬要求下标是从0开始的&#xff0c;和数组的下标是吻合的&#xff0c;存放数据应该从下标0开始n的取值范围是1~10000数组中存放的值的绝对值不超10000&#xff0c;说明int类型就⾜够了找到了输出下标&#xff0c;找不到要输出-1&#xff0c;这⼀点…

SQL server2022的详细安装流程以及简单使用

鉴于SQL Server2008R2版本过于老旧&#xff0c;本文主要讲述如何安装SQL Server 2022。 本文主要详细介绍SQL server2022的详细安装流程以及简单使用&#xff0c;以《数据库系统概论&#xff08;第5版&#xff09;》的第79页—第80页为例&#xff0c;详细介绍如何使用SQL serv…

泰勒公式详解与应用

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 正文 &#x1f4dd; 一句话总结 泰…

Spring Data JPA 中的分页实现:从 BasePage 到 Pageable

文章目录 Spring Data JPA 中的分页实现&#xff1a;从 BasePage 到 Pageable背景&#xff1a;为什么需要分页&#xff1f;认识 BasePage 类深入 toPageable() 方法1. 处理页码和页面大小2. 处理排序方向3. 处理排序字段4. 生成 Pageable 对象 实战&#xff1a;如何使用 BasePa…

Android SystemUI开发(一)

frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUI.java frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java 关键文件 SystemUI 关键服务 简介 Dependency.class&#xff1a;处理系统依赖关系&#xff0c;提供资源或服…

Python----Python爬虫(多线程,多进程,协程爬虫)

注意&#xff1a; 该代码爬取小说不久或许会失效&#xff0c;有时候该网站会被封禁&#xff0c;代码只供参考&#xff0c;不同小说不同网址会有差异 神印王座II皓月当空最新章节_神印王座II皓月当空全文免费阅读-笔趣阁 一、多线程爬虫 1.1、单线程爬虫的问题 爬虫通常被认为…

Linux(ftrace)__mcount的实现原理

Linux 内核调试工具ftrace 之&#xff08;_mcount的实现原理&#xff09; ftrace 是 Linux 内核中的一种跟踪工具&#xff0c;主要用于性能分析、调试和内核代码的执行跟踪。它通过在内核代码的关键点插入探针&#xff08;probe&#xff09;来记录函数调用和执行信息。这对于开…

网络层IP协议

基本概念 主机&#xff1a;有IP地址&#xff0c;但是不进行路由控制的设备。 路由器&#xff1a;有IP地址&#xff0c;又能进行路由控制。 节点&#xff1a;主机和路由器的统称。 协议头格式 4位版本号&#xff1a;指定IP协议的版本。对于IPv4来说&#xff0c;就是4 4位首…

计算机毕业设计SpringBoot+Vue.js在线课程管理系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…