23共享内存

共享内存

是最快的IPC通信方式,不存在数据复制,而是直接内存读写

涉及到多个进程访问,可能出现同时读、写操作,一般采用信号量的方式,进行互斥操作

步骤:

内存共享使用

1:  ftok         使用某个文件做关键字创建key

2:  shmget    使用key 创建(打开)共享内存 shmid

3:  shmat      打开(映射)共享内存. (attach)

4:  memcpy   使用(读写)共享内存

5:  shmdt       释放共享内存. (detach)

6:  shmctl       删除共享内存

创建共享内存

<sys/ipc.h>

<sys/shm.h>

int  shmget(key_t key, size_t sz,  int shmflg)

参数:

key         ftok结果或者 IPC_PRIVATE

sz           共享内存的大小

shmflg    IPC_CREAT | IPC_EXCL | 访问权限

SHM_HUGETLB   内存分配 HUGETLB ‘巨页’内存

shmat

void  *shmat(int shmid, void* shmaddr, int shmflg)

将共享内存连接到指定的进程地址空间,使用共享内存

参数:

shmid         共享内存id

shmaddr     连接的内存地址

NULL:  系统自动选择合适的内存地址(推荐)

非NULL: shmflg 指定 SHM_RND,

把地址减去部分取SHMLBA整数倍

shmaddr – (shmaddr % SHMLBA)

shmflg      SHM_RND

SHM_RDONLY      只读访问

注意:函数出错返回 -1, 不是NULL !!!!!!!!

shmdt

int  shmdt(void *shmaddr)

分离连接到进程地址空间的共享内存, 释放共享内存

共享内存设置

<sys/shm.h>

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

参数:

shmid      共享内存ID

cmd         要做的操作

*buf        操作对应的数据

cmd 参数

IPC_STAT     将内核共享内存的相关数据读取到 buf中

IPC_SET       将buf中的数据设置到共享内存

IPC_RMID     删除共享内存

(以下需要定义宏 _GNU_SOURCE)

IPC_INFO     获取共享内存的系统限制,存入buf中

buf 指向 shminfo 结构体

SHM_INFO   获取共享内存消耗的系统资源消息,存入buf中

buf 指向 shm_info 结构体(和IPC_INFO 不同)

SHM_STAT   获取共享内存相关数据,同 IPC_STAT

shmid 使用内核中维护该共享内存数组的索引值

SHM_LOCK    锁定共享内存,不允许进行交换到虚拟内存

SHM_UNLOCK    解锁共享内存

共享内存数据结构

struct shmid_ds {

struct ipc_perm shm_perm;

size_t                 shm_segsz;  //共享内存大小

time_t                 shm_atime;  //最后调用shmat时间

time_t                 shm_dtime;  //最后调用shmdt时间

time_t                 shm_ctime;  //最后改变共享内存的时间

pid_t                   shm_cpid;    //创建共享内存的进程

pid_t                    shm_lpid;    //最后一次访问共享内存的进程

shmatt_t              shm_nattch;  //当前连接的进程数

}

共享内存中的数据

struct ipc_perm{

key_t  key;               //msgget 的key参数

uid_t   uid                //消息队列所有者 euid

gid_t   gid;              //消息队列所有者 egid

uid_t   cuid;             //消息队列创建者 euid

gid_t   cgid;             //消息队列创建者 egid

unsigned short mode;  //访问权限

unsigned short  __seq;     //序列号

}

系统共享内存数据

struct shminfo {

unsigned long  shmmax;   //共享内存允许最大段数

unsigned long  shmmin;    //共享内存最小段数

unsigned long  shmmni;    //共享内存段最大个数

unsigned long  shmseg;   //进程可以访问的最大段数(未使用)

unsigned long  shmall;     //系统最大共享内存页

}

系统共享内存数据

struct shm_info {

int                 used_ids;          //当前系统中存在的共享内存

unsigned long shm_tot;         //共享内存总页数

unsigned long shm_rss;         //驻留的共享内存页数

unsigned long shm_swp;        //交换的共享内存页数

unsigned long swap_attempts;     //废弃

unsigned long swap_successed;  //废弃

}

例子:

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

#include<sys/ipc.h>

#include<sys/shm.h>

#define SHM_SIZE 0x100000

typedef struct tagInfo

{

char szName[16];

int  age;

char szTel[16];

}INFO_S;

//写操作

void writeMemory(int shmid)

{

//根据shmid连接共享内存,获取首地址

INFO_S *pstAddr;

pstAddr=(INFO_S*)shmat(shmid,NULL,0);

INFO_S stInfo;

int pos;

while(1)

{

//共享内存指定位置写入内容

fprintf(stderr,"input write pos:");

scanf("%d",&pos);

memset(&stInfo,0,sizeof(stInfo));

fprintf(stderr,"input your infomation..\n");

printf("name:");

scanf("%s",stInfo.szName);

printf("age:");

scanf("%d",&(stInfo.age));

printf("szTel:");

scanf("%s",stInfo.szTel);

//将内容放入内存

memcpy(pstAddr+pos,&stInfo,sizeof(stInfo));

}

shmdt(pstAddr);

return ;

}

void readMemory(int shmid)

{

//根据shmid连接共享内存,获取首地址

INFO_S *pstAddr;

pstAddr=(INFO_S*)shmat(shmid,NULL,0);

INFO_S stInfo;

int pos;

while(1)

{

//读取指定位置内容

fprintf(stderr,"input read pos:");

scanf("%d",&pos);

memset(&stInfo,0,sizeof(stInfo));

//读取

memcpy(&stInfo,pstAddr+pos,sizeof(stInfo));

printf("name:%s\n",stInfo.szName);

printf("age:%d\n",stInfo.age);

printf("szTel:%s\n",stInfo.szTel);

}

shmdt(pstAddr);

return  ;

}

// shmid_ds属性

void printShmInfo(struct shmid_ds* pstShm)

{

printf("----------------- SHMID_DS  -----------------\n");

printf("Key        : %#x\n", pstShm->shm_perm.__key);

printf("Ownner uid : %d\n",  pstShm->shm_perm.uid);

printf("Ownner gid : %d\n",  pstShm->shm_perm.gid);

printf("Creater uid: %d\n",  pstShm->shm_perm.cuid);

printf("Creater gid: %d\n",  pstShm->shm_perm.cgid);

printf("Mode       : %#o\n", pstShm->shm_perm.mode);

printf("Seque      : %d\n",  pstShm->shm_perm.__seq);

printf("\n");

printf("Share memory size:%d\n", (int)pstShm->shm_segsz);

printf("Last time for shmat:%d\n", (int)pstShm->shm_atime);

printf("Last time for shmdt:%d\n", (int)pstShm->shm_dtime);

printf("Last time for change:%d\n", (int)pstShm->shm_ctime);

printf("Create share memory id:%d\n", (int)pstShm->shm_cpid);

printf("last read share memory id:%d\n", (int)pstShm->shm_lpid);

printf("Current process number:%d\n", (int)pstShm->shm_nattch);

printf("---------------------------------------------\n");

}

//提示

void Usage()

{

printf("\tstat : print share memory infomation\n");

printf("\tset : reset share memory mode\n");

printf("\texit : exit process\n");

return;

}

//设置操作

void testShmCtl(int shmid)

{

Usage();

struct shmid_ds  stShm;

int iRet;

char szCmd[100] = {};

while(1)

{

fprintf(stderr, "->");

scanf("%s", szCmd);

// stat 当前属性

if (!strcmp(szCmd, "stat"))

{

iRet = shmctl(shmid, IPC_STAT, &stShm);

if (iRet<0)

{

perror("Fail to IPC_STAT!");

continue;

}

printShmInfo(&stShm);

}

//设置mode

else if (!strcmp(szCmd, "set"))

{

int mode;

iRet = shmctl(shmid, IPC_STAT, &stShm);

if (iRet)

{

printf("Fail to IPC_STAT!");

continue;

}

printf("Current Mode: %#o\n", stShm.shm_perm.mode);

fprintf(stderr, "New Mode(eg:600):");

scanf("%o", &mode);

if (mode < 0 || mode > 0777)

{

printf("Mode is invalid(range 0 to 0777).\n");

continue;

}

//修改模式

stShm.shm_perm.mode= mode;

//更新

iRet = shmctl(shmid, IPC_SET, &stShm);

if (iRet)

{

perror("Fail to IPC_SET!");

continue;

}

printf("Set mode success!\n");

}

//退出

else if (!strcmp(szCmd, "exit"))

{

break;

}

else

{

Usage();

}

}

//删除共享内存区域

fprintf(stderr, "Delete share memory [%d]?(y/n):", shmid);

scanf("%s",szCmd);

if (!strcmp(szCmd, "y"))

{

iRet = shmctl(shmid, IPC_RMID, NULL);

if (iRet)

{

perror("Fail to IPC_RMID!");

return;

}

printf("Delete success!\n");

}

return;

}

int main(int argc, char ** argv)

{

if (argc != 2 || (strcmp(argv[1], "w") && strcmp(argv[1], "r")&& strcmp(argv[1], "c" )))

{

printf("Usage: %s [w | r | c]\n", argv[0]);

printf("\t w:  write share memory\n");

printf("\t r : read share memory\n");

printf("\t c : control share memory\n");

return 0;

}

char szFile[] = "123";

//创建key

key_t key = ftok(szFile, 321);

if (key==-1)

{

perror("Fail to ftok!");

return -1;

}

printf("KEY: %#x\n", key);

//创建共享内存

int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0660);

if (shmid < 0)

{

perror("fail to shmget!");

return -1;

}

printf("shmid: %d\n", shmid);

//写

if (argv[1][0] == ‘w‘)

{

writeMemory(shmid);

}

//读

else if(argv[1][0] == ‘r‘)

{

readMemory(shmid);

}

//设置

else

{

testShmCtl(shmid);

}

return 0;

}

原文地址:https://www.cnblogs.com/gd-luojialin/p/9216023.html

时间: 2024-10-29 03:05:08

23共享内存的相关文章

Linux --进程间通信--共享内存

一.共享内存 共享内存是最高效的通信方式,因为不需要一个进程先拷贝到内核,另一个进程在存内核中读取. 二. ipcs -m 查看共享内存 ipcrm -m 删除共享内存 三.主要函数 shmget 创建 shmctl 删除 shmat 挂接 shmdt 取消挂接 ********* man 函数名 查看***** 四.代码实现 comm.h   1 #pragma once   2 #include<stdio.h>   3 #include<stdlib.h>   4 #incl

(转载)linux下的僵尸进程处理SIGCHLD信号Linux环境进程间通信(五): 共享内存(下)

Linux环境进程间通信(五): 共享内存(下) 在共享内存(上)中,主要围绕着系统调用mmap()进行讨论的,本部分将讨论系统V共享内存,并通过实验结果对比来阐述两者的异同.系统V共享内存指的是把所有共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面. 系统调用mmap()通过映射一个普通文件实现共享内存.系统V则是通过映射特殊文件系统shm中的文件实现进程间的共享内

Linux下用信号量实现对共享内存的访问保护

转自:http://www.cppblog.com/zjl-1026-2001/archive/2010/03/03/108768.html 最近一直在研究多进程间通过共享内存来实现通信的事情,以便高效率地实现对同一数据的访问.本文中对共享内存的实现采用了系统V的机制,我们的重点在于通过信号量来完成对不同进程间共享内存资源的一致性访问,共享内存的具体方法请参见相关资料,这里不再赘述. 首先我们先实现最简单的共享内存,一个进程对其更新,另一个进程从中读出数据.同时,通过信号量的PV操作来达到对共享

进程间通信(四)—共享内存

我会用几篇博客总结一下在Linux中进程之间通信的几种方法,我会把这个开头的摘要部分在这个系列的每篇博客中都打出来 进程之间通信的方式 管道 消息队列 信号 信号量 共享存储区 套接字(socket) 进程间通信(三)—信号量传送门:http://www.cnblogs.com/lenomirei/p/5649792.html 进程间通信(二)—消息队列传送门:http://www.cnblogs.com/lenomirei/p/5642575.html 进程间通信(一)—管道传送门:http:

信号,信号量,锁,条件变量,消息通信,共享内存,RPC (一)

在实际项目当中,经常需要把一个功能分成多个子模块实现.那么,这些子模块之间该如何关联起来呢?静态地看,模块可以看作一组完成相同功能的函数:而动态地看,模块可以是一个独立的进程.线程或者一个中断服务或者信号服务例程.根据不同的具体业务实现,它们之间可能是静态调用.动态互斥.同步.唤醒等关系.静态的调用很好实现,上层的函数调用底层的函数即可.那么,动态互斥.同步.唤醒等关系,又该如何实现呢?这就设计到我们将要讨论的信号.进程间消息通信.共享内存.线程互斥同步条件变量.RPC等手段.下面就按照Linu

并发模型—共享内存模型(线程与锁)示例篇

共享内存模型,顾名思义就是通过共享内存来实现并发的模型,当多个线程在并发执行中使用共享资源时如不对所共享的资源进行约定或特殊处理时就会出现读到脏数据.无效数据等问题:而为了决解共享资源所引起的这些问题,Java中引入了同步.锁.原子类型等这些用于处理共享资源的操作; 在本篇文章中,将通过几个Demo来介绍Java的synchronized.lock.atomic相关类等,Java的共享内存并发模型也就体现在同步(synchronized).锁(lock)等这些实现上: 同步: Demo中开启两个

一张图深度解析Linux共享内存的内核实现

一张图深度解析Linux共享内存的内核实现 Sailor_forever  sailing_9806#163.com http://blog.csdn.net/sailor_8318/article/details/39484747 (本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途.任何个人.媒体.其他网站不得私自抄袭:网络媒体转载请注明出处,增加原文链接,否则属于侵权行为.如有任何问题,请留言或者发邮件给sailing_9806#163.com)

【转】Linux共享内存编程实例

原文地址:http://blog.csdn.net/pcliuguangtao/article/details/6526119 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 6

进程通信(共享内存)

共享内存: 用于进程间数据传输,是最高效的,并不提供同步,互斥  shm.h:   1 #include<stdio.h>   2 #include<stdlib.h>   3 #include<sys/ipc.h>   4 #include<sys/shm.h>   5 #include<string.h>   6 #include<sys/wait.h>   7 #include <unistd.h>   8    9