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

来源:互联网 发布:万网和阿里云什么关系 编辑:程序博客网 时间:2024/06/05 19:16
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();#endiftell.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;}




阅读全文
0 0
原创粉丝点击