进程通信系列(13)共享内存系统调用与代码示例

112 篇文章 4 订阅
1 篇文章 0 订阅
1.创建共享内存对象函数

1)函数原型

#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);

返回值: 如果成功,返回共享内存段标识符。如果失败,则返回-1。

key:用户指定的共享内存键值,一般可以设置为IPC_PRIVATE(0)
size:共享内存大小
shmflg: IPC_CREAT, IPC_EXCL等权限组合

2)errno

EINVAL (无效的内存段大小)
EEXIST (内存段已经存在,无法创建)
EIDRM (内存段已经被删除)
ENOENT (内存段不存在)
EACCES (权限不够)
ENOMEM (没有足够的内存来创建内存段)

2、共享内存对象的控制操作

1)函数原型
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

返回: 成功返回0、出错返回-1

2)参数
shmid:共享内存ID
buf:共享内存属性指针
cmd参数取值:
IPC_STAT 获取共享内存段属性
IPC_SET 设置共享内存段属性
IPC_RMID 删除共享内存段
SHM_LOCk 锁定共享内存段页面(页面映射到物理内存不和外存进行换入换出操作)
SHM_ULOCK 解除共享内存段页面的锁定
3.共享内存映射

1) 函数原型

#include <sys/shm.h>
void* shmat(int shmid, char *shmaddr, int shmflg);
返回: 成功返回共享内存段连接到进程中的地址,失败返回-1

2) 参数

shmid:共享内存ID
shmaddr:映射到进程虚拟内存空间的地址,建议设置为0,由操作系统分配。
shmflag:若shmaddr设置为0,则shmflag也设置为0.
SHM_RND
SHMLBA 地址为2的乘方
SHM_RDONLY 只读方式链接

3)errno

EINVAL (无效的IPC ID 值或者无效的地址)
ENOMEM (没有足够的内存)
EACCES (存取权限不够)
4.解除映射
int shmdt(char* shmaddr);
返回:如果失败,则返回-1

参数:

shmaddr:为shmat返回的地址

示例代码:

父进程创建一个子进程,然后父进程向共享内存中写入数据,子进程读取共享内存中的数据。为了保证父进程首先写入数据,其后子进程进行读取这种互斥机制,引入了管道机制,子进程通过等待管道中的数据,将自己阻塞,父进程向共享内存中写入数据后,向管道写入一个字节,触发子进程阻塞结束,从而子进程去读共享内存中数据。

tell.h
#ifndef __TELL_H__
#define __TELL_H__

extern void init();
extern void wait_pipe();

extern void notify_pipe();

extern void destroy_pipe();

#endif


tell.c
#include <stio.h>
#include <stdlib.h>
#include <string.h>
#include "tell.h"

static int fd[2];

void init()
{
  if(pipe(fd) < 0)
  {
    perror("pipe error");
  }
}

void wait_pipe()
{
  char c;
  if(read(fd[0], &c, 1) < 0)
  {
    perror("wait pipe error");
  }
}

void notify_pipe()
{
  char c = 'c';
  if(write(fd[1], &c, 1) !+ 1)
  {
    perror("notify pipe error");
  }
}

void destroy_pipe()
{
  close(fd[0]);
  close(fd[1]);
}


cal_shm.c
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tell.h"

int main()
{
  int shmid;
  if((shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT|IPC_EXCL|0777)) < 0)
  {
    perror("shmget error");
    exit(1);
  }

  pid_t pid;
  init();//初始化管道
  if((pid = fork()) < 0)
  {
    perror("fork error");
    exit(0);
  }
  else if(pid > 0)
  {
    //进行共享内存映射
    int *pi = (int *)shmat(shmid, 0, 0);
    if(pi == (int*)(-1))
    {
      perror("shmat error");
      exit(1);
    }
    //往共享内存中写入数据(通过操作映射的地址即可)
    *pi = 100;
    *(pi + 1) = 200;
    //操作完毕解除共享内存的映射
    shmdt(pi);
    //通知子进程读取数据
    notify_pipe();
    destory_pipe();
    wait(0);
  }
  else
  {//子进程
    wait_pipe();
    //子进程去从共享内存中读取数据
    //子进程进行共享内存的映射
    int *pi = (int*)shmat(shmid, 0, 0);
    if(pi == (int*)(-1))
    {
      perror("shmat error");
      exit(1);
    }
    print("start: %d, end: %d\n", *pi, *(pi +1));
    //读取完毕后解除映射
    shmdt(pi);
    //删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
    destory_pipe();
  }

  return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洪流之源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值