1.什么是共享内存
在前面讲虚拟内存机制时,有讲到Linux的内存映射机制:
初始化虚拟内存区域时,会把虚拟内存和磁盘文件对象对应起来。
由于内存映射机制,一个磁盘文件对象可被多个进程共享访问,也可被多个进程私有访问。
当共享访问时,一个进程的对该对象的修改会显示到其他进程。
当私有访问时,修改时会产生保护故障,内核会拷贝这个私有对象,修改的是这个新对象,其他进程指向的是原来的对象。
所以,共享内存是指不同进程访问同一个逻辑内存。

2.共享内存的使用
Linux提供了一组共享内存API,声明在头文件sys/shm.h中。
1)shmget函数:新建共享内存
int shmget(key_t key,size_t size,int shmflg);
key:共享内存键值,可以理解为共享内存的唯一性标记。
size:共享内存大小
shmflag:创建进程和其他进程的读写权限标识。
返回值:相应的共享内存标识符,失败返回-1

2)shmat函数:连接共享内存到当前进程的地址空间
void *shmat(int shm_id,const void *shm_addr,int shmflg);
shm_id:共享内存标识符
shm_addr:指定共享内存连接到当前进程的地址,通常为0,表示由系统来选择。
shmflg:通常为0
返回值:指向共享内存第一个字节的指针,失败返回-1

3)shmdt函数:当前进程分离共享内存
int shmdt(const void *shmaddr);

4)shmctl函数
和信号量的semctl函数类似,控制共享内存
int shmctl(int shm_id,int command,struct shmid_ds *buf);
shm_id:共享内存标识符
command: 有三个值
      IPC_STAT:获取共享内存的状态,把共享内存的shmid_ds结构复制到buf中。
      IPC_SET:设置共享内存的状态,把buf复制到共享内存的shmid_ds结构。
      IPC_RMID:删除共享内存
buf:共享内存管理结构体。具体结构可参考定义。

3.共享内存需要注意的问题
共享内存没有同步机制,当多个进程同时向共享内存读写数据时,我们需要使用互斥锁,读写锁,信号量,条件变量等来确保数据的一致性。

4.共享内存使用示例

我们编写了两个程序shmread.c,shmwrite.c分别对共享内存读和写。
需要做到可写,然后可读,然后可写,然后可读,循环下去,直到写入的是"end",结束写读进程。
我们使用了前面讲的信号量来处理读写同步的问题。
示例代码如下:

shm_data.h

#pragma once
#define TEXT_SZ 2048
struct shared_use_st
{
char text[TEXT_SZ];
};

shmread.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include"shmdata.h"
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
int sem_id;
int set_semvalue()
{
//用于初始化信号量,在使用信号量前必须这样做
union semun sem_union; sem_union.val = ;
if(semctl(sem_id, , SETVAL, sem_union) == -)
return ;
return ;
} void del_semvalue()
{
//删除信号量
union semun sem_union; if(semctl(sem_id, , IPC_RMID, sem_union) == -)
fprintf(stderr, "Failed to delete semaphore\n");
}
int semaphore_p()
{
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = -;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_p failed\n");
return ;
}
return ;
}
int semaphore_v()
{
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = ;//V()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_v failed\n");
return ;
}
return ;
}
int main()
{
void *shm=NULL;
struct shared_use_st *shared;
int shmid;//共享内存标识符
//创建共享内存
shmid = shmget((key_t),sizeof(struct shared_use_st),|IPC_CREAT);
if(shmid==-)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间
shm = shmat(shmid,,);
if(shm==(void*)-)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("memory attached at %x\n",(int)shm);
//设置共享内存
shared = (struct shared_use_st*)shm; //新建信号量
sem_id = semget((key_t),,|IPC_CREAT); //信号量初始化
if(!set_semvalue())
{
fprintf(stderr,"init failed.\n");
exit(EXIT_FAILURE);
} while()
{
if(!semaphore_p())
exit(EXIT_FAILURE);
fflush(stdout);
printf("you wrote:%s",shared->text);
if(!semaphore_v())
exit(EXIT_FAILURE);
if(strncmp(shared->text,"end",)==)
break;
sleep();
} //删除信号量
del_semvalue(); //把共享内存从当前进程中分离
if(shmdt(shm)==-)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
//删除共享内存
if(shmctl(shmid,IPC_RMID,)==-)
{
fprintf(stderr,"shmctl(IPC_RMID) failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

shmwrite.c

#include<stdio.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<string.h>
#include"shmdata.h"
int sem_id;
int semaphore_p()
{
//对信号量做减1操作,即等待P(sv)
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = -;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_p failed\n");
return ;
}
return ;
}
int semaphore_v()
{
//这是一个释放操作,它使信号量变为可用,即发送信号V(sv)
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = ;//V()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_v failed\n");
return ;
}
return ;
}
int main()
{
sem_id = semget((key_t),,|IPC_CREAT); void *shm = NULL;
struct shared_use_st *shared = NULL;
char buffer[];
int shmid; //创建共享内存
shmid = shmget((key_t),sizeof(struct shared_use_st),|IPC_CREAT);
if(shm==-)
{
fprintf(stderr,"shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间
shm = shmat(shmid,(void*),);
if(shm == (void*)-)
{
fprintf(stderr,"shmat failed\n");
exit(EXIT_FAILURE);
}
printf("memory attached at %x\n",(int)shm);
//设置共享内存
shared = (struct shared_use_st*)shm;
while()
{
if(!semaphore_p())
exit(EXIT_FAILURE);
//向共享内存中写入数据
fflush(stdout);
printf("Enter some text...\n");
fgets(buffer,,stdin);
strncpy(shared->text,buffer,TEXT_SZ);
if(!semaphore_v())
exit(EXIT_FAILURE);
if(strncmp(shared->text,"end",)==)
break;
sleep();
}
//把共享内存从当前进程中分离
if(shmdt(shm)==-)
{
fprintf(stderr,"shmdt failed\n");
exit(EXIT_FAILURE);
}
sleep();
exit(EXIT_SUCCESS);
}

输出结果:

5.共享内存的优缺点
1)进程间通信方便,快速。
2)没有提供同步机制,我们需要使用互斥锁,读写锁,信号量,条件变量等来确保数据的一致性。

Linux共享内存的更多相关文章

  1. Linux 程序设计1:深入浅出 Linux 共享内存

    笔者最近在阅读Aerospike 论文时,发现了Aerospike是利用了Linux 共享内存机制来实现的存储索引快速重建的.这种方式比传统利用索引文件进行快速重启的方式大大提高了效率.(减少了磁盘 ...

  2. linux 共享内存shm_open实现进程间大数据交互

    linux 共享内存shm_open实现进程间大数据交互 read.c #include <sys/types.h> #include <sys/stat.h> #includ ...

  3. linux 共享内存

    共享内存是最高效的IPC机制,因为它不涉及进程之间的任何数据传输.这种高效带来的问题是,我们必须用其他手段来同步进程对共享内存的访问,否则会产生竞态条件.所以,共享内存通常和其他进程间通信方式一起使用 ...

  4. Linux共享内存(二)

    Linux共享内存编程实例 原文链接:http://blog.csdn.net/pcliuguangtao/article/details/6526119 /*共享内存允许两个或多个进程进程共享同一块 ...

  5. linux 共享内存实现

    说起共享内存,一般来说会让人想起下面一些方法:1.多线程.线程之间的内存都是共享的.更确切的说,属于同一进程的线程使用的是同一个地址空间,而不是在不同地址空间之间进行内存共享:2.父子进程间的内存共享 ...

  6. Linux共享内存(一)

    inux系统编程我一直看 <GNU/LINUX编程指南>,只是讲的太简单了,通常是书和网络上的资料结合着来掌握才比较全面 .在掌握了书上的内容后,再来都其他资料 . 原文链接 http:/ ...

  7. 修改linux共享内存大小

    这是实际linux系统显示的实际数据: beijibing@bjb-desktop:/proc/sys/kernel$ cat shmmax  33554432 beijibing@bjb-deskt ...

  8. 【转载】ipcs与Linux共享内存

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

  9. Linux 共享内存 详解

    一.什么是共享内存区 共享内存区是最快的可用IPC形式.它允许多个不相关的进程去访问同一部分逻辑内存.如果需要在两个运行中的进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存区映射到 ...

随机推荐

  1. static声明初始化块的一下注意事项

    通过输出结果,我们可以看到,程序运行时静态初始化块最先被执行,然后执行普通初始化块,最后才执行构造方法.由于静态初始化块只在类加载时执行一次,所以当再次创建对象 hello2 时并未执行静态初始化块.

  2. 2016 - 1- 21 - RunLoop使用(2016-1-24修改一次)&(2016 - 1 - 24 再次修改)

    一:常驻线程 :当需要一个线程一直处理一些耗时操作时,可以让它拥有一个RunLoop.具体代码如下:    1.通过给RunloopMode里加源来保证RunLoop不直接退出. 这里有个很重要得知识 ...

  3. 前端开发者应该知道的 CSS 小技巧

    一些小技巧让你的CSS技术更专业 使用:not()去除导航上不需要的边框 为body添加行高 垂直居中任何元素 逗号分离的列表 使用负nth-child选择元素 使用SVG图标 文本显示优化 在纯CS ...

  4. Kylin上chromium不能用flash的解决命令

    sudo apt-get update sudo apt-get install pepperflashplugin-nonfree sudo update-pepperflashplugin-non ...

  5. 通过 itms-services 协议,发布或者分享 iOS 应用程序

    导读:itms-services 协议常用于 iOS 企业应用的无线部署,这可在不使用 iTunes 的情况下将内部软件发布或者分享给用户. 一.前期准备资料: 1.应用程序 (.ipa) 文件(使用 ...

  6. swift系统学习第二章

    第五节:可选类型 optional //: Playground - noun: a place where people can play import UIKit /* Swift学习第五节 可选 ...

  7. Redis - hash类型操作

    hash 类型操作设置操作:hset:    hset key filed value        创建指定key的filed-value名值对 hsetnx:    hsetnx key file ...

  8. BZOJ3261 最大异或和 (可持久化Trie)

    ; len=; var x,y,z,n,m,tot,lx,i:longint; sum:..maxn] of longint; rt:..maxn] of longint; time,l,r:..ma ...

  9. Inno如何在安装完成时删除指定的文件夹(下的所有文件及子目录)??

    删除安装目录下的任意文件夹及下的所有文件及子目录,或者删除指定目录的文件夹,要如何做到呢?谢谢!! //删除文件    用 DeleteFile 只能删除一个文件,不能使用通配符来删除多个文件Dele ...

  10. 【转】为什么我要用 Node.js? 案例逐一介绍

    原文转自:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...