(一)简单概念

共享内存作为一种进程间通信的方式,其相较于其他进程间通信方式而言最大的优点就是数据传输速率快。其内部实现的方式采用了Linux进程地址空间中的mmap文件映射区,将文件内容直接映射到各自进程的进程地址空间中,进程对各自进程地址空间的访问即可

完成数据通信,由于直接读取内存的方式,故其效率远远快于其他IPC方法,这是共享内存的一大优势。但对于共享内存来说,保证数据同步问题是一个难点,在一般情况下可以采用管道的方式,本节内容的实例代码采用了互斥锁机制。

(二)System V共享内存API函数

(1)int shmget(key_t key, ssize_t size, int oflag)

功能:用于创建共享内存区域。

参数:

key:共享内存的名字,用于唯一确定一个共享内存;

size:创建的共享内存的大小;

oflag:共享内存的读写权限值集合,与文件创建中的mode标志是一样的。同样还可以与IPC_CREAT,IPC_EXCL等标志联合使用。

返回:函数返回共享内存区的标识符。

(2)void *shmat(int shmid, const void *shmaddr, int flag)

功能:将一个创建好的共享内存区附接到进程对应的进程地址空间中。

参数:

shmid:shmget函数的返回值;

shmaddr:将共享内存附接道shmaddr指定的进程地址空间的对应地址上。如果设置为NULL,将由系统指定合法的区域将共享内存映射,这是推荐的做法;

flag:两个可能取值为SHM_RND和SHM_RDONLY。

返回:函数返回映射区的起始地址。

(3)int shmdt(const void *shmaddr)

功能:将共享内存从该进程地址空间中脱离。

参数:

shmaddr:shmat函数的返回值。

返回:如果成功,函数返回0,出错返回-1。

注意:该函数只是将共享内存从进程的地址空间中脱离,不会删除该共享内存区域。并且当一个进程终止时,它当前附接的所有共享内存区都将会自动脱离。

(4)int shmctl(int shmid, int cmd, struct shmid_ds *buf)

功能:提供对共享内存区的多种操作

参数:

shmid:shmget函数的返回值;

cmd:具体操作。取值有1)IPC_RMID:从系统中删除shmid标识的共享内存区并拆除;2)IPC_SET:在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值;3)IPC_START:向调用者返回指定的共享内存区当前的shmid_ds结构。

返回:成功返回0,出错返回-1。

(三)采用互斥锁与共享内存的进程间通信方式

由于共享内存需要解决的一个问题就是数据同步,进程间的同步方式采用信号量可以完成,但我考虑能否采用互斥锁的方式。这里采用互斥锁最初的疑惑为:两个没有近亲关系的进程,如何能够获取到同一个互斥锁(一般互斥锁用于线程间同步的时候比较多,这里也说回来,线程之间本来就是共享数据,所以只需要解决数据同步问题即可,故还没有听说过用共享内存来解决线程通信的 - -。)。

这里来看下,如果设置互斥锁pthread_mutex_t,来使得不同进程可以获取到同一个互斥锁。

对于一个互斥锁pthread_mutex_t来说,有两种方式进行初始化,一种是静态分配,一种是动态初始化。

1)利用宏PTHREAD_MUTEX_INITALIZER来初始化静态分配的互斥锁

pthread_mutex_t mutex = PTHREAD_MUTEX_INITALIZER

2)利用pthread_mutex_init来动态初始化互斥锁

函数原型:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)

这里第一个参数mutex很好理解,就是定义的需要初始化的互斥锁。这里的第二个参数mutexattr代表什么?Linux下互斥锁具有一系列的属性,其中pthread_mutexattr_t结构体定义了一套完整的互斥锁属性。两种常用的属性是pshared和type。其中pshared属性指定了是否允许跨进程共享互斥锁,可选值为:1)PTHREAD_PROCESS_SHARED,互斥锁可以被跨进程共享;2)PTHREAD_PROCESS_PRIVATE,互斥锁只能隶属于一个进程,默认属性。

我们可以通过设置互斥锁自身属性,来达到跨进程共享互斥锁的方法。

结合实例代码来进行分析:

//shmat.h

#ifndef __SHMAT_H__
#define __SHMAT_H__ #include <pthread.h>
#include <string.h>
#include <sys/shm.h>
#include <stdlib.h> #define SM_BUF_SIZE 1024
#define SM_ID 0x1234 struct shmat_msg
{
int flag;
pthread_mutex_t shmat_mutex;
char buf[SM_BUF_SIZE];
}; #endif

头文件声明了共享内存结构体,其中shmat_mutex用于保证对共享内存的互斥访问。

//shmat-read.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h> #include "shmat.h" int main(void)
{
int running = ;
int shm_id, ret;
void *shared_memory = NULL;
struct shmat_msg *sm_msg = NULL; pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); //设置跨进程属性 shm_id = shmget((key_t)SM_ID, sizeof(struct shmat_msg), | IPC_CREAT); //创建共享内存,返回共享内存标识符
if (shm_id < )
{
perror("fail to shmget\n");
exit();
} shared_memory = shmat(shm_id, NULL, ); //映射到进程虚拟地址空间
if (shared_memory == NULL)
{
perror("fail to shmat\n");
exit();
}
sm_msg = (struct shmat_msg*)shared_memory; //转型为shmat_msg数据结构
sm_msg->flag = ;
pthread_mutex_init(&sm_msg->shmat_mutex, &attr); //初始化共享内存的互斥锁 while (running)
{
pthread_mutex_lock(&sm_msg->shmat_mutex); //互斥访问
if (sm_msg->flag)
{
printf("read message : %s\n", sm_msg->buf);
sm_msg->flag = ;
if (strncmp(sm_msg->buf, "exit", ) == )
running = ;
pthread_mutex_unlock(&sm_msg->shmat_mutex);
}
else
{
printf("no data to read, waiting\n");
pthread_mutex_unlock(&sm_msg->shmat_mutex);
sleep();
}
} ret = shmdt(shared_memory); //脱离共享内存的映射
if (ret < )
{
perror("failed to shmdt\n");
exit();
} if (shmctl(shm_id, IPC_RMID, ) < ) //删除共享内存
{
perror("failed to shmctl\n");
exit();
} return ;
}

读文件。设置了共享内存互斥锁为跨进程属性。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h> #include "shmat.h" int main(void)
{
int running = ;
int shm_id, ret;
void *shared_memory = NULL;
struct shmat_msg *sm_msg = NULL; shm_id = shmget((key_t)SM_ID, sizeof(struct shmat_msg), ); //获取共享内存
if (shm_id < )
{
perror("failed to shmget\n");
exit();
} shared_memory = shmat(shm_id, NULL, ); //映射
if (shared_memory == NULL)
{
perror("failed to shmat\n");
exit();
} sm_msg = (struct shmat_msg*)shared_memory;
char buff[]; while (running)
{
pthread_mutex_lock(&sm_msg->shmat_mutex); //获取共享内存的互斥锁
if (sm_msg->flag == )
{
fgets(buff, , stdin);
printf("write sm_msg : %s\n", buff);
strncpy(sm_msg->buf, buff, sizeof(buff));
sm_msg->flag = ;
if (strncmp(sm_msg->buf, "exit", ) == )
running = ;
pthread_mutex_unlock(&sm_msg->shmat_mutex);
}
else
{
printf("sm_msg waiting read\n");
pthread_mutex_unlock(&sm_msg->shmat_mutex);
sleep();
}
} ret = shmdt(shared_memory);
if (ret < )
{
perror("failed to shmdt\n");
exit();
} ret = shmctl(shm_id, IPC_RMID, );
if (ret < )
{
perror("failed to shmctl\n");
exit();
} return ;
}

写文件。

程序运行结果:

其中shmat-write程序运行后会阻塞在fgets等待用户输入。其中shmat-read与shmat-write两个程序抢占lock的时机是不确定的,可能同一个程序会多次抢占互斥锁,但由于没有内容可读或可写,则睡眠等待。

unlock解锁后,操作系统下次调度哪个进程加锁是不一定的,如果需要在满足一定条件后才被调度可以采用条件变量(但一般都是在多线程环境下了)。

System V共享内存介绍的更多相关文章

  1. Linux进程通信之System V共享内存

    前面已经介绍过了POSIX共享内存区,System V共享内存区在概念上类似POSIX共享内存区,POSIX共享内存区的使用是调用shm_open创建共享内存区后调用mmap进行内存区的映射,而Sys ...

  2. 阐述linux IPC(五岁以下儿童):system V共享内存

    [版权声明:尊重原创.转载请保留源:blog.csdn.net/shallnet 要么 .../gentleliu,文章学习交流,不用于商业用途]         system V共享内存和posix ...

  3. UNIX环境高级编程——System V 共享内存区

    共享内存区域是被多个进程共享的一部分物理内存.如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信.共享内存是进程间共享数据的一种最 ...

  4. Linux IPC实践(9) --System V共享内存

    共享内存API #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int ...

  5. php进程(线程)通信基础--System V共享内存

    PHP默认情况没有开启功能,要支持该功能在编译PHP的时候要加入下面几个选项  System V消息,--enable-sysvmsg   System V信号量支持,--enable-sysvsem ...

  6. System V 共享内存区

    1.概述 系统调用mmap通过映射一个普通文件实现共享内存.System V 则是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信.也就是说,每个共享内存区域对应特殊文件系统shm中的一个文 ...

  7. 共享内存之——system V共享内存

    System V 的IPC对象有共享内存.消息队列.信号灯(量). 注意:在IPC的通信模式下,不管是共享内存.消息队列还是信号灯,每个IPC的对象都有唯一的名字,称为"键(key)&quo ...

  8. Linux system v 共享内存

    system v 共享内存 #include <sys/types.h> #include <sys/shm.h> int shmget(key_t key, size_t s ...

  9. System V共享内存

    目录 1. 概述 2. System V共享内存API shmget shmat shmdt shmctl 3. 简单的程序 代码实现 common.h shmcreate.c shmrmid.c s ...

随机推荐

  1. poj2018——Best Cow Fences

    Description Farmer John's farm consists of a long row of N (1 <= N <= 100,000)fields. Each fie ...

  2. 【题解】Atcoder ARC#97 F-Monochrome Cat

    好zz啊我……(:д:) 首先我们可以删掉所有只有黑色节点的子树(一定不会遍历到), 且注意到每一个点你一定只会经过一遍.然后又考虑如果起点和终点相同,那么总次数实际上已经固定了:就是遍历整棵树(每一 ...

  3. [JSOI2007]重要的城市 floyd:最短路计数

    ---题面--- 题解: 其实感觉还是比较妙的,第一眼看题想到floyd统计最短路条数, 注意到对于任意两点x,y而言,floyd将会枚举其最短路所可能经过的所有中转点, 因此我们可以直接分别统计对于 ...

  4. [TJOI2013]最长上升子序列 平衡树

    其实是一道性质题. 首先观察到插入的数是递增的, 那么根据上升子序列的性质, 我们的非法情况就是统计到了在一个数前面的后插入的数, 但是由于插入的数是递增的,显然插入这个数后,这个数就是最大的,所以除 ...

  5. Android Apk的反编译与代码混淆

    一.反编译 1.获取工具: 既然是反编译,肯定要用到一些相关的工具,工具可以到这里下载,里面包含三个文件夹,用于反编译,查看反编译之后的代码: 其实这两工具都是google官方出的,也可在google ...

  6. HDU.3342 Legal or Not (拓扑排序 TopSort)

    HDU.3342 Legal or Not (拓扑排序 TopSort) 题意分析 裸的拓扑排序 根据是否成环来判断是否合法 详解请移步 算法学习 拓扑排序(TopSort) 代码总览 #includ ...

  7. HDOJ.1800 Flying to the Mars(贪心+map)

    Flying to the Mars 点我挑战题目 题意分析 有n个人,每个人都有一定的等级,高等级的人可以教低等级的人骑扫帚,并且他们可以共用一个扫帚,问至少需要几个扫帚. 这道题与最少拦截系统有异 ...

  8. Java 匿名内部类 只能访问final变量的原因

    文章来源:http://blog.sina.com.cn/s/blog_4b6f8d150100qni2.html 1)从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方 ...

  9. spring全局异常处理 自定义返回数据结构

    在写api接口中,正常返回和异常错误返回我们都希望很清楚的将这些信息清楚的返回给用户,出现异常情况下需要清楚的知道是参数异常还是未知异常,而不是返回一个不正确的数据结构. 所以此处只针对写api接口时 ...

  10. 深度学习---tensorflow简介

    个core可以有不同的代码路径.对于反向传播算法来说,基本计算就是矩阵向量乘法,对一个向量应用激活函数这样的向量化指令,而不像在传统的代码里会有很多if-else这样的逻辑判断,所以使用GPU加速非常 ...