#一、常用函数
#函数系列头文件
```
#include
#include
#include
```
#ftok():
系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
```
key_t ftok( char * fname, int id );//当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。
```

应用举例:

key_t key = ftok(".", 2);//通过ftok函数得到id值存在key中,下面创建共享内存时会用到

shmget() :

用于创建共享内存

int shmget(key_t key, size_t size, int shmflg);	//成功返回共享内存的ID,出错返回-1

应用举例:

int shmid = shmget(key, 100, IPC_CREAT | IPC_EXCL | 0666);
//创建共享内存,成功返回共享内存的ID,出错返回-1,IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的共享内存,如果共享内存已存在,返回一个错误。

(1)第一个参数key是长整型(唯一非零),系统建立IPC通讯 ( 消息队列、 信号量和 共享内存) 时必须指定一个ID值。通常情况下,该id值通过ftok函数得到,由内核变成标识符,要想让两个进程看到同一个信号集,只需设置key值不变就可以。

(2)第二个参数size指定共享内存的大小,它的值一般为一页大小的整数倍(未到一页,操作系统向上对齐到一页,但是用户实际能使用只有自己所申请的大小)。

(3)第三个参数shmflg是一组标志,创建一个新的共享内存,将shmflg 设置了IPC_CREAT标志后,共享内存存在就打开。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的共享内存,如果共享内存已存在,返回一个错误。一般我们会还或上一个文件权限

shmctl():

用于操作共享内存

int shmctl(int shm_id, int cmd, struct shmid_ds *buf); //成功返回0,出错返回-1

(1)第一个参数,shm_id是shmget函数返回的共享内存标识符。

(2)第二个参数,cmd是要采取的操作,它可以取下面的三个值 :

  • IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。

  • IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值

  • IPC_RMID:删除共享内存段

(3)第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。 shmid_ds结构至少包括以下成员

struct shmid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
};

shmat():

用于创建共享存储段之后,将进程连接到它的地址空间

void *shmat(int shm_id, const void *shm_addr, int shmflg); //成功返回指向共享存储段的指针,出错返回-1

应用举例:

void *pshm = shmat(shmid, 0, 0);//挂接操作,成功返回指向共享存储段的指针,出错返回-1
if (*(int *)pshm == -1) {//查看挂接是否成功如果出错返回-1,报错
printf("shmat error!\n");
exit(0);
}

(1)第一个参数,shm_id是由shmget函数返回的共享内存标识。

(2)第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

(3)第三个参数,shm_flg是一组标志位,通常为0

shmdt():

用于分离操作

int shmdt(const void *shmaddr); //成功返回0,出错返回-1
//addr参数是以前调用shmat时的返回值

二、函数实践

在设计实验中,运用共享内存的四个主要函数shmaget函数,shmat函数,shmdt函数,shmctl函数之后,读出传送数据的文件可以视为服务器read.c,传送数据相当于客户端文件write.c,实现进程之间的相互通信。

write.c程序段(将数据写入共享空间):

//write.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <signal.h>
struct Msg {
int flag;//0为读,1为写
char content[104];
};
int shmid;
void *pshm;
void Handle(int s) {//监听函数
if (s == 2)
{
shmdt(pshm);
shmctl(shmid, IPC_RMID, 0);
exit(0);
}
}
int main() {
signal(2, Handle);//按ctrl+c键退出时会处理这个消息,进行共享内存卸载、删除操作,最后exit(0)退出程序 key_t key = ftok(".", 2);//通过ftok函数得到id值存在key中 shmid = shmget(key, 100, IPC_CREAT | IPC_EXCL | 0666);/*创建共享内存,成功返回共享内存的ID,出错返回-1,IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的共享内存,如果共享内存已存在,返回一个错误。*/ pshm = shmat(shmid, 0, 0);//挂接操作,成功返回指向共享存储段的指针,出错返回-1 if (*(int *)pshm == -1) {//查看挂接是否成功如果出错返回-1,报错
printf("shmat error!\n");
exit(0);
}
memset(pshm, 0, 100);//初始化
struct Msg *msg = (struct Msg *)pshm;
msg->flag = 1;
while (1) {
if (msg->flag == 1) {//当为1时写消息,此时读文件中不能操作此共享内存
printf("请输入内容至共享内存:");
scanf("%s", msg->content);
msg->flag = 0;//当写消息后flag置为0,让读文件开始执行读操作,此时写文件不能进行写操作
}
else {
sleep(1);
}
}
return 0;
}

read.c程序段(将数据同步从共享空间读出):

//read.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <signal.h>
struct Msg {
int flag;
char content[104];
};
int main() { key_t key = ftok(".", 2);
int shmid = shmget(key, 0, 0);//通过ftok函数得到id值存在key中 void *pshm = shmat(shmid, 0, 0);//挂接操作,成功返回指向共享存储段的指针,出错返回-1 if (*(int *)pshm == -1) {//查看挂接是否成功如果出错返回-1,报错
printf("shmat error!\n");
exit(0);
} struct Msg * msg = (struct Msg *)pshm;
while (1) {
if (msg->flag == 0) {//当为0时读消息,此时写文件中不能操作此共享内存
printf("从共享内存收到 : %s\n", msg->content);
msg->flag = 1;
}
else {
sleep(1);
}
} return 0;
}

运行结果与分析:



在程序运行中,同时打开两个终端,分别运行write和read程序,便能发现write将内容写入共享内存,而同时read进程自行同步将共享内存中的数据读出,进而实现进程通信 。

设计的这个实验的优点是方便简单,效率非常的高,有着很高的灵活性。但若有多个进程同时读取,可能会出现错误,解决该问题需要有一种进程同步的机制,或者借助其他手段来进行进程间的同步工作,将在接下来的学习中会进一步解决。

三、参考博客与资料

sky_Mata 的 进程间通信方式——共享内存: https://blog.csdn.net/skyroben/article/details/72625028

清清飞扬 的 linux ftok()函数: https://www.cnblogs.com/joeblackzqq/archive/2011/05/31/2065161.html

学习笔记:Linux下共享内存的方式实现进程间的相互通信的更多相关文章

  1. Windows中利用共享内存来实现不同进程间的通信

    Windows中利用共享内存来实现不同进程间的通信 一.msdn详细介绍 https://docs.microsoft.com/zh-cn/windows/win32/memory/sharing-f ...

  2. 萌新笔记——linux下查看内存的使用情况

    windows上有各种软件可以进行"一键加速"之类的操作,释放掉一些内存(虽然我暂时不知道是怎么办到的,有待后续学习).而任务管理器也可以很方便地查看各进程使用的内存情况,如下图: ...

  3. linux下共享内存mmap和DMA(直接访问内存)的使用 【转】

    转自:http://blog.chinaunix.net/uid-7374279-id-4413316.html 介绍Linux内存管理和内存映射的奥秘.同时讲述设备驱动程序是如何使用“直接内存访问” ...

  4. linux 下共享内存

    一.共享内存相关知识 所谓共享内存,就是多个进程间共同地使用同一段物理内存空间,它是通过将同一段物理内存映射到不同进程的 虚拟空间来实现的.由于映射到不同进程的虚拟空间中,不同进程可以直接使用,不需要 ...

  5. Linux 程序设计学习笔记----Linux下文件类型和属性管理

    转载请注明出处:http://blog.csdn.net/suool/article/details/38318225 部分内容整理自网络,在此感谢各位大神. Linux文件类型和权限 数据表示 文件 ...

  6. MongoDB学习笔记—Linux下搭建MongoDB环境

    1.MongoDB简单说明 a MongoDB是由C++语言编写的一个基于分布式文件存储的开源数据库系统,它的目的在于为WEB应用提供可扩展的高性能数据存储解决方案. b MongoDB是一个介于关系 ...

  7. python学习笔记——多进程中共享内存Value & Array

    1 共享内存 基本特点: (1)共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝. (2)为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将 ...

  8. Java学习笔记——Linux下安装配置tomcat

    朝辞白帝彩云间,千里江陵一日还. 两岸猿声啼不住,轻舟已过万重山. ——早发白帝城 首先需要安装配置JDK,这里简单回顾下.Linux下用root身份在/opt/文件夹下创建jvm文件夹,然后使用ta ...

  9. LINUX学习笔记——LINUX下EXP命令全库备份数据库文件

    LINUX下EXP命令全库备份数据库文件 1)建立备份目录,目录操作权限授权给Oracle用户 mkdir /backup  --创建backup文件夹 cd  /   --进入cd语句 ls  -l ...

随机推荐

  1. jupyter notebook new Python3报错:Permission denied: Untitled.ipynb,修改workspace

    点击新建Python文件即弹出弹窗显示 Permission denied: Untitled.ipynb 看到Permission denied 尝试是权限问题进行解决,各种百度结果都是对文件进行权 ...

  2. 【转】通过BeanNameAutoProxyCreator改变臃肿代码

    https://www.cnblogs.com/zdd-java/p/7861824.html 前言: 最近接手了一个项目,大概过了下需求,然后打开项目准备开搞的时候发现一个问题,这个项目是提供res ...

  3. Educational Codeforces Round 41 (Rated for Div. 2) D. Pair Of Lines (几何,随机)

    D. Pair Of Lines time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  4. vue---子调父 $emit (把子组件的数据传给父组件)

    ps:App.vue 父组件  Hello.vue 子组件 ps:App.vue 父组件 Hello.vue 子组件 <!--App.vue :--> <template> & ...

  5. RxJava 以及 Android 中的通用线程解决方案、并发与线程安全

    关于RxJava如今是熟到发紫了,所以对于它底层的动作机制的了解是迫在眉睫了,费话不多说,直接开始. 这里还是以之前获取个人github仓库列表为例,用retrofit+rxjava,也是实际项目中用 ...

  6. [转]神奇的 SQL 之层级 → 为什么 GROUP BY 之后不能直接引用原表中的列

    原文:https://www.cnblogs.com/youzhibing/p/11516154.html 这篇文章,对group by的讲解不错 -------------------------- ...

  7. 使用springboot和easypoi进行的数据导出的小案例

    在这个案例中使用的有springboot和easypoi进行数据导出到excel中 yml文件是这样的: server: port: 8080 spring: datasource: url: jdb ...

  8. React 之 高阶组件的理解

    1.基本概念 高阶组件是参数为组件,返回值为新组件的函数. 2.举例说明 ① 装饰工厂模式 组件是 react 中的基本单元,组件中通常有一些逻辑(非渲染)需要复用处理.这里我们可以用高阶组件对组件内 ...

  9. 51NOD 1452 - 加括号

    DP预处理每个区间的值,再枚举括号位置就好了 #include <bits/stdc++.h> using namespace std; typedef long long ll; con ...

  10. ElementUI 之 Cascader 级联选择器指定 value label

    ElementUI 的 Cascader 级联选择器个人觉得很好用,但是对 :options="options" 里的数据格式是有特定要求的:input 框显示的值是 option ...