LINUX共享内存的创建与使用

1.操作系统API

shm为前缀 为 shared memory
创建共享内存段或者使用已创建的共享内存段( shmget())
将进程附加到已经创建的内存段中(shmat())
从已连接的共享内存段分离进程(shmdt())
对共享内存段执行控制操作(shmctl())
头文件
#include <sys/ipc.h>
#include <sys/shm.h>

//函数原型
1.int shmget(key_t key, size_t size, int shmflg)
//输入参数
key 0 — 建立新共享内存对象
>0 — 获取已创建的共享内存对象
size 0 — 只获取共享内存时指定为0
>0 —指定创建的共享内存的大小 (单位字节)
shmflg 0 — 取共享内存标识符,若不存在则函数会报错
IPC_CREAT — 当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL — 如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错
// 返回值
成功:返回共享内存的标识符
出错:返回 -1,错误原因通过errno获取
常见错误代码
EINVAL:参数size小于SHMMIN或大于SHMMAX
EEXIST:预建立key所指的共享内存,但已经存在
EIDRM:参数key所指的共享内存已经删除
ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL)
ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT
EACCES:没有权限
ENOMEM:核心内存不足

2.void *shmat(int shmid, const void *shmaddr, int shmflg)
3.int shmdt( void *addr);
4.int shmctl(int shmid, int cmd, struct shmid_ds *buf)

另外 命令 ipcs –m 可以查看当前系统下的共享内存段

2.创建demo

实现内容为进程1创建共享内存,并写入内容,进程2读取共享内存。
程序1 写入内容

#include <stdio.h>
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
 #include <unistd.h>
#define SHM_KEY  7500  
#define SHM_SIZE 1024
int main()
{   
    int  shmid = -1;
    char * ptr = NULL;
    shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT|0666);
    if(shmid == -1)
    {
        std::cout<<"errno = "<<errno<<std::endl;
        return -1;
    }
    std::cout<<"shmid = "<<shmid<<std::endl;
    ptr = (char *)shmat(shmid,NULL,0);
    if(ptr == NULL)
    {
        std::cout<<"errno = "<<errno<<std::endl;
        return -1;
    }
    memset(ptr, 0, SHM_SIZE);
    char *pstr = (char *)"Hello shm!";
    
    memcpy(ptr,pstr,strlen(pstr));
    shmdt(ptr);
}

程序2 读取写入的内容

#include <stdio.h>
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string.h>
 #include <unistd.h>
#define SHM_KEY  7500  
#define SHM_SIZE 1024
int main()
{   
    int  shmid = -1;
    char * ptr = NULL;
    shmid = shmget(SHM_KEY, SHM_SIZE, 0666); //仅读取 没有该内存段则直接结束
    if(shmid == -1)
    {
        std::cout<<"errno = "<<errno<<std::endl;
        return -1;
    }
    std::cout<<"shmid = "<<shmid<<std::endl;
    ptr = (char *)shmat(shmid,NULL,0);
    if(ptr == NULL)
    {
        std::cout<<"errno = "<<errno<<std::endl;
        return -1;
    }
    std::cout<<"get shared memeory is:"<<ptr<<std::endl;
    shmdt(ptr);
}

通过这个demo可以知道,两个进程是通过唯一表示SHM_KEY连接起来的。

利用ipcs -m 命令可以看到,即使进程结束了,共享内存的内容也是还在的
系统共享内存
直接 ipcrm -m shmid 即可以删除该段共享内存

程序在 shmdt后或者程序结束后会将 nattch 减一 如果当前共享内存段没有程序访问则返回 -1 。

问:多进程同时访问修改共享内存会出现什么结果?
写了两个Write进程同上面的Write,只是把字符串分别改为了

char *pstr = (char *)"Hello shm Write 1!";

char *pstr = (char *)"Hello shm Write 2!";

读进程还是一样,写了一个脚本分别执行两个写进程和一个读进程

#!/bin/bash
echo "MySharedMemoryTest!!"
$PWD/./Write1&
$PWD/./Write2&
$PWD/./Read&

Output是随机的结果为Write2结果为Write1
这说明,光有共享内存,没有办法满足进程间同步的需求,是不可控的。所以共享内存一般与信号量共同使用。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值