[Linux]共享内存

共享内存是UNIX提供的进程间通信手段中速度最快的一种,也是最快的IPC形式。为什么是最快的呢,因为数据不需要在客户进程和服务器进程之间复制,所以是最快的一种IPC。这是虚存中由多个进程共享的一个公共内存块。

两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。

如果服务器进程正在将数据放入到共享存储区,则在它做完这一操作之前,客户进程不应当去取这些数据。通常信号量用于同步共享存储访问。

由于共享内存是通过映射到同一块物理内存后进行的通信,因此肯定需要映射到内存的函数和解除映射的函数,主要有以下几种

#define SHMAT       21//空间映射:把上面打开的内存区域连接到用户的进程空间中  
#define SHMDT       22//解除映射:将共享内存从当前进程中分离  
#define SHMGET      23//创建打开一个内存区域  
#define SHMCTL      24//内存区域的控制:包括初始化和删除内存区域。

注意:共享内存通信本身没有提供同步机制,如果同时被多个进程进行映射和写操作,会导致破坏该内存空间的内容。因此在实际应用过程中,需要通过其他的机制来同步对共享内存的访问。比如信号量。

内核为每个共享存储段维护着一个结构,该结构至少要为每个共享存储段包含以下成员:

struct shmid_ds 
{struct ipc_perm shm_perm; //ipc结构体size_t shm_segsz;  //请求的sizepid_t shm_lpid;   //0pid_t shm_cpid;   //创建者pidshmatt_t shm_nattch; //当前挂载数time_t shm_atime;  //0time_t shm_dtime; //0time_t shm_ctime;  //设置为当前时间
};

1.调用的第一个函数为shmget:

#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
//key是创建共享内存id的唯一标识符,size为共享存储段的长度,以字节为单位,通常将其向上取为系统页长的整数倍。如果不是整页,则最后剩余部分是不可用的。flag表示相应的权限位。

2.shmctl函数对共享内存段执行多种操作

#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
//IPC_RMID:从系统中删除该共享存储段。

3.一旦创建了共享存储段,进程就可调用shmat将其连接到它的地址空间中。

void *shmat(int shmid,const void* addr,int flag);
//返回若成功,返回指向共享存储段的指针,出错返回-1
//如果成功执行,那么内核将使与该共享存储段相关的shmid_ds结构中的shm_nattch计数器值加1;当对共享存储段的操作已经结束时,则调用shmat与该段分离。这里并没有从系统中删除相关的数据结构,该标识符和ipc数据结构仍然存在。
int shmdt(const void* addr);  //为挂载时的addr
//如果调用成功,则使与该共享存储段相关的shmid_ds结构中的shm_nattch计数器值减1

具体代码实现:

//comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>#define PATHNAME "."
#define PROJ_ID 0X6667int CreateShm(int size);
int GetShm(int size);int destroyShm(int shmid);#endif   //_COMM_H_
//comm.c
#include"comm.h"int CommShm(int size,int flags)
{key_t key = ftok(PATHNAME,PROJ_ID);if(key < 0){perror("ftok");return -1;}int shmid = shmget(key,size,flags); if(shmid < 0){perror("shmget");return -2;}return shmid;
}int CreateShm(int size)
{return CommShm(size,IPC_CREAT|IPC_EXCL|0666);
}
int GetShm(int size)
{return CommShm(size,IPC_CREAT);
}
int destroyShm(int shmid)
{if(shmctl(shmid,IPC_RMID,NULL) < 0){perror("shmctl");return -1;}return 0;
}
//server.c
#include"comm.h"int main()
{int shmid = CreateShm(4096);
//  printf("hello server!\n");char *addr = shmat(shmid,NULL,0);if(addr == NULL){return 1;}int i = 0;char s = 'a';while(1){addr[i] = s;s++;}addr[i] = 0;sleep(4);shmdt(addr);printf("shm quit!\n");return 0;
}
//client.c
#include"comm.h"int main()
{int shmid = GetShm(4096);//printf("hello client!\n");char *addr = shmat(shmid,NULL,0);if(addr == NULL)return 2;printf("%s",addr);sleep(10);shmdt(addr);    printf("shm quit!\n");return 0;
}

运行结果:

这里写图片描述

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

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

相关文章

僵尸进程的产生,危害和解决方案

概念 僵死状态&#xff08;Zombies&#xff09;是一个比较特殊的状态。 当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会以终止状态保持在进程表中&#xff0c;并且会一直在等待父进程读取退出状态代码。所以&#xff0c;只要子进程退出&…

CString string 转换

https://www.cnblogs.com/HappyEDay/p/7016162.html

[Linux]gdb调试多进程多线程例程

gdb相信学linux的同学已经比较熟悉了吧&#xff0c;它是linux下代码调试工具。我们在写c语言&#xff0c;c的代码时经常会用到&#xff0c;它有一些常用的调试命令: run&#xff08;r&#xff09;&#xff1a;运行程序&#xff0c;如果有断点在下一个断点处停止 start&#xf…

gdb调试常用命令速查(段错误调试)

编译程序时需要加上-g&#xff0c;之后才能用gdb进行调试&#xff1a;gcc -g main.c -o main gdb中命令&#xff1a; 回车键&#xff1a;重复上一命令 &#xff08;gdb&#xff09;help&#xff1a;查看命令帮助&#xff0c;具体命令查询在gdb中输入help 命令,简写h &…

C语言字符串 小记

#include "stdafx.h" #include <iostream> #include <string.h> using namespace std;int _tmain(int argc, _TCHAR* argv[]) {char str1[] "12345"; // ""括起来的字符串 会在末尾增加 \0 cout << sizeof(str1) << en…

[Linux]守护进程(精灵进程)

一、守护进程是什么 守护进程是生存期很长的一种进程&#xff0c;可以说它是7*24小时工作的。&#xff08;什么是7*24&#xff0c;一周7天&#xff0c;每天24小时&#xff0c;这不就是一年365天一直在工作嘛&#xff0c;还搞的这么诙谐&#xff0c;哈哈&#xff09;。它们常常…

linux命令行界面下ctrl 常用组合键速查表

Ctrlz 暂停正在运行的程序 Ctrll 清屏 Ctrld 结束输入或退出shell Ctrla 切换到命令行开始 Ctrle 切换到命令行末尾 Ctrlu 删除光标前内容 Ctrlk 删除光标后内容 Ctrlxu 撤销操作

[Linux]运输层的端口

既然提到端口&#xff0c;我们就来分析一下为什么要使用端口的缘由吧。我们首先要知道的是&#xff0c;运输层有复用和分用的功能。应用层所有的应用进程都可以通过运输层再传送到IP层&#xff0c;这就是复用。运输层从IP层收到数据后必须交付到指明的应用进程&#xff0c;这就…

浅谈shell中的clear命令实现

NAME(名称) clear - 清除终端屏幕 SYNOPSIS(总览) clear DESCRIPTION(描述) clear可以在允许的情况下清屏. 它会在环境变量中查找终端的类型, 然后到terminfo数据库中找出清屏的方法. 《man手册》 #include <stdio.h>int clear_main(int argc, char **argv) {/* Th…

C++ 对引用的理解

引用可以看做是数据的一个别名&#xff0c;通过这个别名和原来的名字都能够找到这份数据引用必须在定义的同时初始化&#xff0c;并且以后也要从一而终&#xff0c;不能再引用其它数据&#xff0c;这有点类似于常量&#xff08;const 变量&#xff09;。引用变量 里面 实际存储…

[Linux]ARP协议

概念&#xff1a; 1. ARP协议(地址解析协议):由IP地址转换为MAC地址的协议。IP地址&#xff1a;网络号主机号。MAC地址&#xff1a;数据链路层的物理地址&#xff08;硬件地址&#xff09;。IP协议使用了ARP协议&#xff0c;因此被划归为网络层&#xff0c;但其用途是从网络层…

Makefile使用及多文件gdb 调试

文件内容 [koulocalhost makefile]$ cat 1.c #include "3.h" int main() {key_t key ftok(".",1);printf("%d\n",add(1,2));return 0; }[koulocalhost makefile]$ cat 2.c #include "3.h" int add(int a, int b) {return a b; } [k…

C++ 对引用的理解2

1.指针就是数据或代码在内存中的地址&#xff0c;指针变量指向的就是内存中的数据或代码。这里有一个关键词需要强调&#xff0c;就是内存&#xff0c;指针只能指向内存&#xff0c;不能指向寄存器或者硬盘&#xff0c;因为寄存器和硬盘没法寻址。 2.其实 C 代码中的大部分内容…

Ubuntu各版本主要差异

Ubuntu各版本主要差异 (重定向自Ubuntu &#xff0c; kubuntu与xubuntu的差别 ) Ubuntu官方考虑到使用者的不同需求&#xff0c;提供各种不同的发行版。这几种发行版本的差别在于桌面环境和预设安装的软体不同&#xff0c;但套件库是采用一样的&#xff0c;所以您当然可以在安…

[Linux]CRC校验

CRC(Cyclic Redundancy Check),循环冗余校验码&#xff0c;是数据通信领域中最常用的一种差错校验码&#xff0c;其特征是信息字段和校验字段的长度可以任意选定。 CRC校验步骤&#xff1a; CRC分为两部分&#xff0c;前部分为信息码&#xff0c;后部分为校验码&#xff1b;设…

visual studio 2015 配置好qt5后, 第一次运行出现 无法打开源文件“QtWidgets/QApplication”和无法运行rc.exe的解决方案

无法打开源文件“QtWidgets/QApplication” a.在工程中右击项目&#xff0c;点击属性。 b.选择VC目录->包含目录 c.选择Qt安装目录中的头文件包含目录&#xff0c;一般为Qt版本号/版本号/编译器名/include 比如&#xff1a;E:\Qt\Qt5.6.3\5.6.3\msvc2015\include 在C\C>附…

怎么在vs中查看一个数组的所有元素

在监视窗口&#xff0c;我们想要查看所有的数组元素。 这个时候 int arr[] {1,2,3} arr只显示1 正确的方法 arr&#xff0c;10

[Linux]NAT和代理服务器

1. NAT&#xff1a;&#xff08;Network Address Translation&#xff09;是网络地址转换。 我们有这样一种场景&#xff0c;在专用网内部的一些主机本来已经分配到了本地IP地址&#xff0c;但现在又想和因特网上的主机通信&#xff0c;我们可以设法再申请一些全球IP地址&…

使用 C++的第三方库 jsoncpp的步骤以及出现的问题

Jsoncpp 是一个json解析库 下载地址为&#xff1a; http://sourceforge.net/projects/jsoncpp/ 方法一&#xff1a;使用Jsoncpp生成的lib文件 解压上面下载的Jsoncpp文件&#xff0c;在jsoncpp-src-0.5.0/makefiles/vs71目录里找到jsoncpp.sln&#xff0c;用VS2008版本编译&am…

常用的友元重载运算符OSTREAM

对<<运算符重载&#xff0c;让他能和cout一起显示对象内容。 显示值可以使用show()&#xff0c;但是使用cout<<更方便。 ostream类对该运算符进行了重载&#xff0c;将其转换成输出工具。 cout就是一个ostream的对象&#xff0c;他可以自动识别所有的c基本类型。…