[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,一经查实,立即删除!

相关文章

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

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

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

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

浅谈shell中的clear命令实现

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

[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…

[Linux]CRC校验

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

python字符串系列

1.find方法用于在长串中查找子串&#xff0c;返回子串中最左位置的下标&#xff0c;如果没找到&#xff0c;则返回-1 2.join方法用于在队列中添加元素 3.lower返回字符串的小写字母版 4.replace返回字符串中所有匹配项均被替换之后得到字符串 5.split将字符串分割成序列 6.stri…

linux网络编程Internet Socket地址,套接字,和函数

文章内容节选《linux/UNIX 系统网络编程》 Internet domain socket地址有两种&#xff1a;IPv4 IPv6 IPv4被存储在结构体中&#xff0c; 该结构体在 netinet/in.h 中进行定义 cd usr/include/netinet/in.h struct in_addr {in_addr_t s_addr; //32位IPv4地址 }struct so…

浅谈socket网络编程函数参数(一)

socket函数解析 概念: 每个进程的进程空间里都有一个socket描述符表。套接字描述符表属于一个进程&#xff0c;而socket地址结构位于操作系统的内核缓冲。 函数原型 #include <sys/socket.h>int socket(int domain, int type, int protocol);函数参数 family参数 默…

为什么计算机起始时间是1970年1月1日

1969年8月&#xff0c;贝尔实验室的程序员肯汤普逊利用妻儿离开一个月的机会&#xff0c;开始着手创造一个全新的革命性的操作系统&#xff0c;他使用B编译语言在老旧的PDP-7机器上开发出了Unix的一个版本。随后&#xff0c;汤普逊和同事丹尼斯里奇改进了B语言&#xff0c;开发…

TCP三次挥手四次握手(面试总结)

1、 为什么建立连接协议是三次握手&#xff0c;而关闭连接却是四次握手呢&#xff1f; 全双工通信。 这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后&#xff0c;它可以把ACK和SYN&#xff08;ACK起应答作用&#xff0c;而SYN起同步作用&#xff09;放在一个…

csdn怎么快速转载别人的文章

如何转载 用谷歌浏览器加载文章地址&#xff0c;打开文章F12打开Developer Tools&#xff0c;并打开Elements页面 将文章开头部分的文字作为关键字在Elements界面搜索 以此文为例&#xff1a;http://blog.csdn.net/aggressive_snail/article/details/54375876 搜索找了好久关…

解释性语言和汇编性语言对比

解释性语言和编译型语言的区别和不同解释性语言编译型语言概念计算机不能直接的理解高级语言&#xff0c;只能直接理解机器语言&#xff0c;所以必须要把高级语言翻译成机器语言&#xff0c;计算机才能执行高级语言的编写的程序。翻译的方式有两种&#xff0c;一个是编译&#…

C++ 菱形继承 的 对象模型01

先看 普通菱形继承 #include <iostream> #include <string> using namespace std; class Animal {int a_age; }; class Sheep : public Animal {}; class Tuo : public Animal {}; class SheepTuo : public Sheep, public Tuo {}; void test1() {cout << …

伙伴算法

通常情况下&#xff0c;一个高级操作系统必须要给进程提供基本的、能够在任意时刻申请和释放任意大小内存的功能&#xff0c;就像malloc 函数那样&#xff0c;然而&#xff0c;实现malloc 函数并不简单&#xff0c;由于进程申请内存的大小是任意的&#xff0c;如果操作系统对ma…

CRC冗余校验举例和原理

什么是CRC校验&#xff1f;CRC即循环冗余校验码&#xff1a;是数据通信领域中最常用的一种查错校验码&#xff0c;其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查&#xff08;CRC&#xff09;是一种数据传输检错功能&#xff0c;对数据进行多项式计算&#xff0c…

C++ 多态原理初步01

当父类 Animal 的speak 前面加上 virtual 关键字之后&#xff0c;这个speak函数就变成了虚函数&#xff0c;Animal类结构发生了变化&#xff0c; 有了一个vfptr &#xff08;虚函数指针&#xff09;&#xff0c;指向了vftable&#xff08;虚函数表&#xff09;, 这个虚函数表里…