#一、常用函数
#函数系列头文件
```
#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. Git 日常命令

    克隆项目:git clone addr dir   切换分支,分支并没有 git checkout -b production origin/production 分支已存在,单纯切换分支 git c ...

  2. SQL SERVER-端口Port

    Quick cheat sheet for port numbers used by SQL Server services or services that SQL Server may depen ...

  3. .symtab

    参考:剖析.o文件ELF组成 目标文件 .symtab中记录的符号是从.s文件来的,所以.s这个汇编文件很关键. .symtab所记录符号的种类 示例代码 a.c ; static float a_v ...

  4. Stages — 研发过程可视化建模和管理平台

    Stages 是德国Method park公司的产品,用于帮助企业定义.管理.发布.控制.优化其研发过程,同时使其研发过程符合CMMI.ASPICE.ISO26262等标准.Stages的核心理念是把 ...

  5. 个性化排序算法实践(一)——FM算法

    因子分解机(Factorization Machine,简称FM)算法用于解决大规模稀疏数据下的特征组合问题.FM可以看做带特征交叉的LR. 理论部分可参考FM系列,通过将FM的二次项化简,其复杂度可 ...

  6. How to parse unix timestamp to time.Time

      The time.Parse function does not do Unix timestamps. Instead you can use strconv.ParseInt to parse ...

  7. C++——宏观把控

    跟看所有的书一样,我们都要求第一遍泛读,宏观把控书本内容,C++依旧如此进行.看到前面这几章的时候感觉非常熟悉,因为能让我联想到很多以前学习的VB.C#等的知识,感觉轻松很多,原来我已经学过了很多东西 ...

  8. celery timeout的拦截

    0X01 场景 celery任务超时报错,想查看是传入哪一类数据运行时导致的超时(哪一个插件),但是该报错难以拦截. [2019-06-30 17:23:21,070: ERROR/MainProce ...

  9. Helm:kubernetes应用包管理工具

    概要 Helm:kubernetes应用包管理工具 K8s部署应用的时候,应用会通过yaml描述信息调用K8s-api:Helm即是管理这些Yaml的应用包管理工具 组成 Helm包含5个部分 Hel ...

  10. 自定义MVC--增删改查

    使用自定义mvc框架完成CRUD操作 1.通用分页的jar.自定义mvc框架.自定义标签 导入jar.导入之前写好的pageTag.自定义mvc.xml 1.1导入需要用到的jar包 1.2导入之前已 ...