Linux16 ---共享内存、操作函数、使用示例

news2024/9/20 10:31:13

一、共享内存

1、

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

在这里插入图片描述

共享内存实际是操作系统在实际物理内存中开辟的一段内存。
共享内存实现进程间通信,是操作系统在实际物理内存开辟一块空间,一个进程在自己的页表中,将该空间和进程地址空间上的共享区的一块地址空间形成映射关系。另外一进程在页表上,将同一块物理空间和该进程地址空间上的共享区的一块地址空间形成映射关系。
当一个进程往该空间写入内容时,另外一进程访问该空间,会得到写入的值,即实现了进程间的通信。
要实现进程间通信需要两个进程能够看到同一块空间,系统开辟的共享内存就是两进程看到的同一资源。

二、共享内存函数的介绍

1、shmget

int shmget(key_t key, size_t size, int shmflg);

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

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

4、shmctl – 控制共享内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmctl() :控制共享内存
shmctl() :成功返回 0,失败返回-1
cmd: IPC_RMID

在这里插入图片描述

三、共享内存使用示例

1、进程a向共享内存写入数据,进程b从共享内存中读取数据并显示;

代码:
main.c :

//main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/shm.h>
int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
	char *s=(char *)shmat(shmid,NULL,0);
	if(s==(char *)-1)
	{
		exit(1);
	}
	strcpy(s,"hello");
	shmdt(s);
	exit(0);
}

test.c :

//test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/shm.h>

int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
	char *s=(char *)shmat(shmid,NULL,0);
	if(s==(char *)-1)
	{
		exit(1);
	}
	printf("%s",s);
	shmdt(s);
	shmctl(shmid,IPC_RMID,NULL);
	exit(0);
}

可见,原本运行./test不会打印东西,运行完./main之后,再运行./test就能输出hello。
./main将hello写入到共享内存中后,./test才能将共享内存中的数据打印出来。

在这里插入图片描述

2、进程a从键盘循环获取数据并拷贝到共享内存中,进程b从共享内存中获取并打印(不加控制)

代码:

不加控制的使用会出问题:

main.c :

//不加控制的使用,改为循环从键盘获取,循环读取数据
//main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/shm.h>
int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
	char *s=(char *)shmat(shmid,NULL,0);
	if(s==(char *)-1)
	{
		exit(1);
	}
	// strcpy(s,"hello");
	while(1)
	{
		printf("input :\n");
		char buff[128]={0};
		fgets(buff,128,stdin);
		strcpy(s,buff);
		if(strncmp(buff,"end",3)==0)
		{
			break;
		}
	}
	shmdt(s);
	exit(0);
}
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/shm.h>
int main()
{
	int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
	assert(shmid!=-1);
	
	char *s=(char *)shmat(shmid,NULL,0);
	if(s==(char *)-1)
	{
		exit(1);
	}
	
	// printf("%s",s);
	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);
}
//不加控制的使用会出问题;

那为什么会出现这个问题呢?
没有对两者进行控制。
所以,必须要使用信号量;

一个信号量不可以:
在这里插入图片描述

必须需要两个信号量进行控制:

在这里插入图片描述

3、进程a从键盘循环获取数据并拷贝到共享内存中,进程b从共享内存中获取并打印(加信号量进行控制)

在这里插入图片描述

1)示例代码:

sem.h

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>

union semun
{
    int val;
};

void sem_init();//初始化
void sem_p(int index);//p操作,index为下标
void sem_v(int index);//v操作
void sem_destroy();//销毁

sem.c

#include "sem.h"

#define  SEM_NUM  2 //宏,创建信号量的数量

static int semid = -1;//信号量的id

void sem_init()//共享内存的创建
{
    semid = semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);//全新创建,1234为自己定义,0600为权限
    
    if (semid == -1 )//创建失败,可能已经被创建或是真的创建失败
    {
    	//尝试获取,可能被创建
        semid = semget((key_t)1234,SEM_NUM,0600);
        if ( semid == -1)
        {
            printf("semget err\n");
            return;
        }
    }
    else//全新创建成功
    {
        int arr[SEM_NUM] = {1,0};
        for( int i = 0; i < SEM_NUM; i++ )//对创建的信号量进行初始值设定
        {
            union semun a;
            a.val = arr[i];
            if ( semctl(semid,i,SETVAL,a) == -1 )//全新创建成功,就初始化
            {
                printf("semctl err\n");
            }
        }
    }
}

void sem_p(int index)//p操作
{
    if ( index < 0 || index >= SEM_NUM )
    {
        return;
    }
    struct sembuf buf;
    buf.sem_num = index;
    buf.sem_op = -1;//p
    buf.sem_flg = SEM_UNDO;
    if ( semop(semid,&buf,1) == -1 )
    {
        printf("sem p err\n");
    }
}

void sem_v(int index)//v操作
{
    if ( index < 0 || index >= SEM_NUM )
    {
        return;
    }
    struct sembuf buf;
    buf.sem_num = index;
    buf.sem_op = 1;//v
    buf.sem_flg = SEM_UNDO;
    if ( semop(semid,&buf,1) == -1 )
    {
        printf("sem v err\n");
    }
}

void sem_destroy()//销毁
{
    if ( semctl(semid,0,IPC_RMID) == -1 )
    {
        printf("semctl del err\n");
    }
}

a.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include "sem.h"
int main()
{
    int  shmid = shmget((key_t)1234,256,0600|IPC_CREAT);//创建/获取共享内存
    if ( shmid == -1 )
    {
        printf("shmget err\n");
        exit(0);
    }

    char* s = (char*)shmat(shmid,NULL,0);
    if ( s == (char*)-1 )
    {
        printf("shmat err\n");
        exit(0);
    }

    sem_init();//2  1,0
    while( 1 )
    {
        printf("input\n");
        char buff[128] = {0};
        fgets(buff,128,stdin);
        sem_p(0);
        strcpy(s,buff);
        sem_v(1);
        if ( strncmp(buff,"end",3) == 0 )
        {
            break;
        }
    }

    shmdt(s);
    exit(0);
}

b.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include "sem.h"
int main()
{
    int shmid = shmget((key_t)1234,256,IPC_CREAT|0600);
    if ( shmid == -1 )
    {
        printf("shmget err\n");
        exit(0);
    }

    char* s = shmat(shmid,NULL,0);
    if ( s == (char*)-1)
    {
        printf("shmat err\n");
        exit(0);
    }

    sem_init();
    while( 1 )
    {
        sem_p(1);
        if ( strncmp(s,"end",3) == 0 )
        {
            break;
        }
        printf("read:%s",s);
        sem_v(0);
    }

    shmdt(s);
    sem_destroy();
    shmctl(shmid,IPC_RMID,NULL);
}

在这里插入图片描述

2)代码运行

编译(记得带上sem.c):

在这里插入图片描述
记得检查共享内存、信号量是否销毁移除:
ipcs命令查看
ipcs -s :移除信号量
ipcs -m:移除
共享内存
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(二)Easyexcel 的使用(读取数据到map集合中)

前面讲述了使用实体类的方式绑定excel表头的方式进行读取和写入操作&#xff0c;是比较简单的&#xff0c;那么由于表头可能会变&#xff0c;那么就不能使用绑定实体类的方式进行了&#xff0c;于是搜索百度一番&#xff0c;借鉴别人的博客&#xff0c;使用map集合的方式进行读…

一文详解Cookie 和 Session 会话技术

目录 Cookie Session 分布式下Seesion的不足 Cookie 定义&#xff1a;Cookie是服务器发送到浏览器&#xff0c;并保存在浏览器端的一小块数据。浏览器下次访问该服务器时&#xff0c;会自动携带该数据块&#xff0c;将其发送给服务器。 作用&#xff1a;由于HTTP是无状态的&…

tomcat修改默认端口详细步骤(包含运行测试)

前言&#xff1a; 在tomcat端口被占用或者需要把默认的8080端口换成其他的端口&#xff0c;就可以修改默认端口。 一、修改步骤 1.打开tomacat的文件位置--conf目录 2.找到server.xml右键打开方式选择记事本打开 3.找到这个文件的Connector port "8080" 大概位…

TVM 中文站正式上线!最全机器学习模型部署「参考书」它来了

内容一览&#xff1a; 近日&#xff0c;由 MLC 社区志愿者共同翻译校对的 TVM 中文文档正式发布&#xff0c;现已托管至超神经官网 Hyper.AI。 关键词&#xff1a; TVM 开源 机器学习编译器 本文首发自微信公众号&#xff1a;HyperAI超神经 面世5年&#xff0c;TVM成备受追捧的…

tensorflow2.0 学习笔记:一、神经网络计算

mooc课程Tensorflow2.0 笔记 人工智能三学派 行为主义&#xff1a;基于控制论&#xff0c;构建感知-动作控制系统&#xff08;自适应控制系统&#xff09;符号主义&#xff1a;基于算数逻辑表达式&#xff0c;求解问题时先把问题描述为表达式&#xff0c;再求解表达式&#x…

AMD EPYC(霄龙)Genoa服务器 | 综合评测

9004 | EYPC | 9654P | AMD 9654 | 7703 | Genoa | Intel 当生命科学、医药研发、东数西算、数据分析、数据挖掘、算力、数据中心、智算中心、遥感测绘、地质遥感等场景逐渐成熟&#xff0c;上层应用场景改变了底层硬件基础&#xff0c;计算、存储、网络架构的迭代升级和调整融…

win11连接共享打印机错误0x00000709

连接共享打印机出现错误0x00000709是常见的打印机错误了&#xff0c;但是用户升级到win11系统之后还遇到了同样的问题&#xff0c;这该如何解决&#xff1f;今天小编就给大家带来详细的解决办法&#xff0c;一起来看看。 方法一、卸载补丁 Win10卸载有问题的补丁KB5006667或KB5…

java项目-第145期ssm汽车在线销售系统-java毕业设计_计算机毕业设计

java项目-第145期ssm汽车在线销售系统-java毕业设计_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm汽车在线销售系统》 该项目分为2个角色&#xff0c;管理员和用户。 用户可以浏览前台,包含功能有&#xff1a; 首页、车辆信息、新闻资讯、留言反馈、我的、跳…

OpenCV图像处理——直方图

总目录 图像处理总目录←点击这里 十二、直方图 12.1、原理 cv2.calcHist(images,channels,mask,histSize,ranges) images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]channels: 同样用中括号括来它会告函数我们统幅图 像的直方图。如果…

电容笔哪个品牌好?十大电容笔知名品牌

如今&#xff0c;电容笔越来越受欢迎&#xff0c;性能也越来越好。如何挑选出一款物美价廉的电容笔&#xff0c;就成了一件非常头疼的事情。许多人将其用于日常生活&#xff0c;所以人们都在寻找更好、更经济的电容笔。那么&#xff0c;电容笔的牌子是最便宜、最值得我们入手呢…

骁龙AR2平台解析:分布式架构开启轻量化AR眼镜新时代

在今天的骁龙峰会2022上&#xff0c;高通面向轻量化AR眼镜推出了专属SoC&#xff1a;第一代骁龙AR2平台&#xff0c;这套方案将骁龙XR1、骁龙XR2的单片式方案&#xff0c;改为多芯片分布式SoC方案&#xff0c;同时融合了分离式渲染&#xff0c;实现一整套的AR/VR与智能手机、PC…

Leetcode 学习记录 数组和字符串 习题2

搜索插入位置 给定一个有序数组nums&#xff0c;数组中没有重复元素。搜索指定元素target在数组中插入位置。题目说如果target存在于数组中&#xff0c;直接返回index&#xff0c;如果不在返回应该插入的位置。要求在O&#xff08;logn&#xff09;的时间复杂度内完成。 因为…

DevOps Master课程总结:学习没有捷径(送DevOps安灯正确方法)

​1.摆正学习态度 “活到老&#xff0c;学到老”&#xff0c;学习是贯穿所有人一生的一件事情 。俗话说&#xff1a;“师傅领进门,修行在个人。”的意思是&#xff1a;有了师傅的指教&#xff0c;学生的技艺可以进步很快&#xff0c;但是&#xff0c;单单靠师傅是不够的&#x…

【线程】多线程编程

目录 一、概念 二、线程函数 1.pthread_create 2.pthread_exit 3.pthread_join 4.pthread_cancel 三、线程的使用 1.线程的基本操作 2.理解并发运行 一、概念 线程是程序中完成一个独立任务的完整执行序列&#xff0c;即一个可调度的实体。根据运行环境和调度者的身…

Maven基础概念【仓库和坐标】这篇看完懂了

Maven下载 官网: Welcome to Apache Maven 下载地址: Maven – Download Apache Maven 01 仓库&#xff1a; 仓库:用于存储资源&#xff0c;包含各种jar包 ​ ​ 仓库&#xff1a;用于存储资源&#xff0c;包含各种jar包 仓库分类&#xff1a; ♦ 本地仓库&#xff1a;自己电…

4_Git

一、Git学习网站 廖雪峰大神 Git 教程Git-flow 包教不包会阮一峰-常用 Git 命令清单 二、Git简介 1.Git是什么 分布式版本控制系统 2.版本控制 3.集中式 vs 分布式 4.Git简史 5.工作区、暂存区、版本库 流程 工作区&#xff1a;写代码 --> git add --> 暂存区 --…

uniapp项目搭建 请求配置

uniapp项目搭建 请求配置请求配置utils/request/index.js代码分析几个常用的方法配置文件的引入编写接口,并测试调用每个人项目用的请求接口不一样,这里就看下实现思路就好了 请求配置 在 uniapp 当中有封装好的 request 插件, request插件地址 在项目的 utils/request/index.…

【华为设备命令最全大合集,快快收藏】

01 华为交换机基础配置命令 01 常用命令视图 02 创建VLAN //用户视图&#xff0c;一般display命令查看信息比较多。 system-view //准备进入系统视图。 [Huawei]vlan 100 //创建vlan 100。 [Huawei-vlan100]quit //退回系统视图。 03 将端口加入到vlan中 [Huawei] interf…

数字源表如何助力miniled光电性能测试

概述 LED在光电子领域中是一种能将电能转化为光能的半导体二极管&#xff0c;包括砷化镓LED(红光)、磷化镓LED(绿光)、氮化镓LED(蓝光)等。Mini LED&#xff0c;则是指尺寸为50-200微米的LED芯片(参照《Mini LED商用显示屏通用技术规范》的定义)&#xff0c;介于小间距LED和Mic…

软件配置 | mac M1 上 imagemagick 的安装

本文简单记录在 mac M1 上安装 Imagemagick 的过程及其简单使用。 2022 / 11 / 16 软件配置 | mac M1 上 imagemagick 的安装安装brew1.2.make参考链接ImageMagick 是免费软件&#xff0c;以随时可用的二进制分发版或源代码形式提供&#xff0c;您可以在开放和专有应用程序中使…