导航:首页 > 操作系统 > linux设置共享内存

linux设置共享内存

发布时间:2022-06-08 02:19:22

A. 架构师进阶:linux进程间如何共享内存

共享内存 IPC 原理
共享内存进程间通信机制主要用于实现进程间大量的数据传输,下图所示为进程间使用共享内存实现大量数据传输的示意图:

640

共享内存是在内存中单独开辟的一段内存空间,这段内存空间有自己特有的数据结构,包括访问权限、大小和最近访问的时间等。该数据结构定义如下:

from /usr/include/linux/shm.h
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms 操作权限 */
int shm_segsz; /* size of segment (bytes) 段长度大小 */
__kernel_time_t shm_atime; /* last attach time 最近attach时间 */
__kernel_time_t shm_dtime; /* last detach time 最近detach时间 */
__kernel_time_t shm_ctime; /* last change time 最近change时间 */
__kernel_ipc_pid_t shm_cpid; /* pid of creator 创建者pid */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator 最近操作pid */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */|
};
两个进程在使用此共享内存空间之前,需要在进程地址空间与共享内存空间之间建立联系,即将共享内存空间挂载到进程中。

系统对共享内存做了以下限制:

#define SHMMAX 0x2000000 /* max shared seg size (bytes) 最大共享段大小 */

#define SHMMIN 1 /* min shared seg size (bytes) 最小共享段大小 */

#define SHMMNI 4096 /* max num of segs system wide */

#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))|

define SHMSEG SHMMNI /* max shared segs per process */

Linux 共享内存管理
1.创建共享内存

#include <sys/ipc.h> #include <sys/shm.h>
/*
* 第一个参数为 key 值,一般由 ftok() 函数产生
* 第二个参数为欲创建的共享内存段大小(单位为字节)
* 第三个参数用来标识共享内存段的创建标识
*/

int shmget(key_t key, size_t size, int shmflg);
2.共享内存控制

#include <sys/ipc.h> #include <sys/shm.h>
/*
* 第一个参数为要操作的共享内存标识符
* 第二个参数为要执行的操作
* 第三个参数为 shmid_ds 结构的临时共享内存变量信息
*/

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
3.映射共享内存对象

系统调用 shmat() 函数实现将一个共享内存段映射到调用进程的数据段中,并返回内存空间首地址,其函数声明如下:

#include <sys/types.h>

#include <sys/shm.h>
/*
* 第一个参数为要操作的共享内存标识符
* 第二个参数用来指定共享内存的映射地址,非0则为此参数,为0的话由系统分配
* 第三个参数用来指定共享内存段的访问权限和映射条件
*/

void *shmat(int shmid, const void *shmaddr, int shmflg);
4.分离共享内存对象

在使用完毕共享内存空间后,需要使用 shmdt() 函数调用将其与当前进程分离。函数声明如下:

#include <sys/types.h>

#include <sys/shm.h>
/*
* 参数为分配的共享内存首地址
*/

int shmdt(const void *shmaddr);

共享内存在父子进程间遵循的约定
1.使用 fork() 函数创建一个子进程后,该进程继承父亲进程挂载的共享内存。

2.如果调用 exec() 执行一个新的程序,则所有挂载的共享内存将被自动卸载。

3.如果在某个进程中调用了 exit() 函数,所有挂载的共享内存将与当前进程脱离关系。

程序实例
申请一段共享内存,父进程在首地址处存入一整数,子进程读出。

#include

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/types.h>

#include

#include

#define SHM_SIZE 1024

int main()

{

int shm_id, pid;

int *ptr = NULL;
/* 申请共享内存 */

shm_id = shmget((key_t)1004, SHM_SIZE, IPC_CREAT | 0600);
/* 映射共享内存到进程地址空间 */

ptr = (int*)shmat(shm_id, 0, 0);

printf("Attach addr is %p ", ptr);

*ptr = 1004;

printf("The Value of Parent is : %d ", *ptr);

if((pid=fork()) == -1){

perror("fork Err");

exit(0);

}

else if(!pid){
printf("The Value of Child is : %d ", *ptr);
exit(0);
}else{
sleep(1);
/* 解除映射 */

shmdt(ptr);
/* 删除共享内存 */

shmctl(shm_id, IPC_RMID, 0);
}
return 0;
}
输出结果:

640

B. 如何设置linux的共享内存

首先先使用shmget建立一块共享内存,然后向该内存中写入数据并返回该共享内存shmid
使用另一个程序通过上一程序返回的shmid读该共享内存内的数据
建立共享内存并写入数据的程序

#include<stdio.h>
#include<string.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<errno.h>
voidget_buf(char*buf)
{
inti=0;
while((buf[i]=getchar())!=' '&&i<1024)
i++;
}
intmain(void)
{
intshmid;
shmid=shmget(IPC_PRIVATE,sizeof(char)*1024,IPC_CREAT|0666);
if(shmid==-1)
{
perror("shmget");
}
char*buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
get_buf(buf);
printf("%d ",shmid);
return0;
}
读取数据的程序
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
intmain(intargc,char**argv)
{
intshmid;
shmid=atoi(argv[1]);
char*buf;
if((int)(buf=shmat(shmid,NULL,0))==-1)
{
perror("shmat");
exit(1);
}
printf("%s ",buf);
shmdt(buf);
return0;
}

命令行的第一个参数设为第一个程序输出的数字

使用完以后可以使用
ipcrm -m 19562507
来删除该共享内存

C. linux下通过shmget创建的共享内存,是属于用户空间还是内核空间

属于用户空间. shmat后返回的地址空间属于用户空间, 不同进程可以将同一物理内存区域映射到各自的用户空间中。该空间可以随意读写。note: 一个小屁进程,在用户态时,是没有权限操作内核空间的。

虚拟地址空间=用户空间+内核空间。

D. 一般来说,在linux中使用共享内存的流程应该怎样

可以使用samba协议。Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。SMB是一种在局域网上共享文件和打印机的一种通信协议,它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。具体配置步骤如下:
步骤1:安装samba
sudo apt-get install samba samba-common-bin
步骤2:新建共享目录并设置权限
sudo mkdir /home/share
sudo chmod 777 /home/share
步骤3:修改配置文件
sudo nano /etc/samba/smb.conf
在smb.conf最后添加:
[share]
path = /home/share
browseable = yes
writable = yes
comment = smb share test
public = no#yes无需密码 no需要密码
步骤4:添加远程访问用户
sudo useradd smbuser
sudo smbpasswd -a smbuser
步骤5:重新启动服务
sudo service samba restart
对于windows操作系统,在资源管理器里输入\\Linux的IP地址,会提示输入上述步骤设置的用户名和密码,输入正确后即可访问分享内容。

E. LINUX共享内存如何实现

首先,美化Linux并启动桥接器。SAMBA服务可以在Linux环境中共享。

F. linux内核如何勾选共享内存

所谓共享内存就是使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。其他进程能把同一段共享内存段“连接到”他们自己的地址空间里去。所有进程都能访问共享内存中的地址。如果一个进程向这段共享内存写了数据,所做的改动会即时被有访问同一段共享内存的其他进程看到。共享内存的使用大大降低了在大规模数据处理过程中内存的消耗,但是共享内存的使用中有很多的陷阱,一不注意就很容易导致程序崩溃。

1.超过共享内存的大小限制?

在一个linux服务器上,共享内存的总体大小是有限制的,这个大小通过SHMMAX参数来定义(以字节为单位),您可以通过执行以下命令来确定 SHMMAX 的值:

# cat /proc/sys/kernel/shmmax

如果机器上创建的共享内存的总共大小超出了这个限制,在程序中使用标准错误perror可能会出现以下的信息:

unable to attach to shared memory

>解决方法:

1、设置 SHMMAX

SHMMAX 的默认值是 32MB 。一般使用下列方法之一种将 SHMMAX 参数设为 2GB :

通过直接更改 /proc 文件系统,你不需重新启动机器就可以改变 SHMMAX 的默认设置。我使用的方法是将以下命令放入 />etc/rc.local 启动文件中:

echo "2147483648" > /proc/sys/kernel/shmmax

您还可以使用 sysctl 命令来更改 SHMMAX 的值:sysctl -w kernel.shmmax=2147483648

最后,通过将该内核参数插入到 /etc/sysctl.conf 启动文件中,您可以使这种更改永久有效:echo "kernel.shmmax=2147483648" >> /etc/sysctl.conf

2、设置 SHMMNI

G. linux共享内存使用的过程

Linux共享内存使用的过程?

一、什么是共享内存
顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,例如前面说到的信号量。

二、共享内存的使用
与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h中。
1、shmget函数
该函数用来创建共享内存,它的原型为:
int shmget(key_t key, size_t size, int shmflg);
第一个参数,与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1.

不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调用shmget函数并提供一个键,再由系统生成一个相应的共享内存标识符(shmget函数的返回值),只有shmget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。

第二个参数,size以字节为单位指定需要共享的内存容量

第三个参数,shmflg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。

H. linux共享内存的分配

进程通过调用shmget(Shared Memory GET,获取共享内存)来分配一个共享内存块。
该函数的第一个参数是一个用来标识共享内存块的键值。彼此无关的进程可以通过指定同一个键以获取对同一个共享内存块的访问。不幸的是,其它程序也可能挑选了同样的特定值作为自己分配共享内存的键值,从而产生冲突。用特殊常量IPC_PRIVATE作为键值可以保证系统建立一个全新的共享内存块。
该函数的第二个参数指定了所申请的内存块的大小。因为这些内存块是以页面为单位进行分配的,实际分配的内存块大小将被扩大到页面大小的整数倍。
第三个参数是一组标志,通过特定常量的按位或操作来shmget。这些特定常量包括:
IPC_CREAT:这个标志表示应创建一个新的共享内存块。通过指定这个标志,我们可以创建一个具有指定键值的新共享内存块。
IPC_EXCL:这个标志只能与 IPC_CREAT 同时使用。当指定这个标志的时候,如果已有一个具有这个键值的共享内存块存在,则shmget会调用失败。也就是说,这个标志将使线程获得一个“独有”的共享内存块。如果没有指定这个标志而系统中存在一个具有相同键值的共享内存块,shmget会返回这个已经建立的共享内存块,而不是重新创建一个。
模式标志:这个值由9个位组成,分别表示属主、属组和其它用户对该内存块的访问权限。其中表示执行权限的位将被忽略。指明访问权限的一个简单办法是利用<sys/stat.h>中指定,并且在手册页第二节stat条目中说明了的常量指定。例如,S_IRUSR和S_IWUSR分别指定了该内存块属主的读写权限,而 S_IROTH和S_IWOTH则指定了其它用户的读写权限。 下面例子中shmget函数创建了一个新的共享内存块(当shm_key已被占用时则获取对一个已经存在共享内存块的访问),且只有属主对该内存块具有读写权限,其它用户不可读写。
int segment_id = shmget (shm_key, getpagesize (), IPC_CREAT | S_IRUSR| S_IWUSR ); 如果调用成功,shmget将返回一个共享内存标识符。如果该共享内存块已经存在,系统会检查访问权限,同时会检查该内存块是否被标记为等待摧毁状态。

I. 共享内存 linux下怎么跑

linux 共享内存实现

说起共享内存,一般来说会让人想起下面一些方法:
1、多线程。线程之间的内存都是共享的。更确切的说,属于同一进程的线程使用的是同一个地址空间,而不是在不同地址空间之间进行内存共享;
2、父子进程间的内存共享。父进程以MAP_SHARED|MAP_ANONYMOUS选项mmap一块匿名内存,fork之后,其子孙进程之间就能共享这块内存。这种共享内存由于受到进程父子关系的限制,一般较少使用;
3、mmap文件。多个进程mmap到同一个文件,实际上就是大家在共享文件pagecache中的内存。不过文件牵涉到磁盘的读写,用来做共享内存显然十分笨重,所以就有了不跟磁盘扯上关系的内存文件,也就是我们这里要讨论的tmpfs和shmem;

tmpfs是一套虚拟的文件系统,在其中创建的文件都是基于内存的,机器重启即消失。
shmem是一套ipc,通过相应的ipc系统调用shmget能够以指定key创建一块的共享内存。需要使用这块内存的进程可以通过shmat系统调用来获得它。
虽然是两套不同的接口,但是在内核里面的实现却是同一套。shmem内部挂载了一个tmpfs分区(用户不可见),shmget就是在该分区下获取名为"SYSV${key}"的文件。然后shmat就相当于mmap这个文件。
所以我们接下来就把tmpfs和shmem当作同一个东西来讨论了。

tmpfs/shmem是一个介于文件和匿名内存之间的东西。
一方面,它具有文件的属性,能够像操作文件一样去操作它。它有自己inode、有自己的pagecache;
另一方面,它也有匿名内存的属性。由于没有像磁盘这样的外部存储介质,内核在内存紧缺时不能简单的将page从它们的pagecache中丢弃,而需要swap-out;(参阅《linux页面回收浅析》)

对tmpfs/shmem内存的读写,就是对pagecache中相应位置的page所代表的内存进行读写,这一点跟普通的文件映射没有什么不同。
如果进程地址空间的相应位置尚未映射,则会建立到pagecache中相应page的映射;
如果pagecache中的相应位置还没有分配page,则会分配一个。当然,由于不存在磁盘上的源数据,新分配的page总是空的(特别的,通过read系统调用去读一个尚未分配page的位置时,并不会分配新的page,而是共享ZERO_PAGE);
如果pagecache中相应位置的page被回收了,则会先将其恢复;

对于第三个“如果”,tmpfs/shmem和普通文件的page回收及其恢复方式是不同的:
page回收时,跟普通文件的情况一样,内核会通过prio_tree反向映射找到映射这个page的每一个pagetable,然后将其中对应的pte清空。
不同之处是普通文件的page在确保与磁盘同步(如果page为脏的话需要刷回磁盘)之后就可以丢弃了,而对于tmpfs/shmem的page则需要进行swap-out。
注意,匿名page在被swap-out时,并不是将映射它的pte清空,而是得在pte上填写相应的swap_entry,以便知道page被换出到哪里去,否则再需要这个page的时候就没法swap-in了。
而tmpfs/shmem的page呢?pagetable中对应的pte被清空,swap_entry会被存放在pagecache的radix_tree的对应slot上。

等下一次访问触发pagefault时,page需要恢复。
普通文件的page恢复跟page未分配时的情形一样,需要新分配page、然后根据映射的位置重新从磁盘读出相应的数据;
而tmpfs/shmem则是通过映射的位置找到radix_tree上对应的slot,从中得到swap_entry,从而进行swap-in,并将新的page放回pagecache;

这里就有个问题了,在pagecache的radix_tree的某个slot上,怎么知道里面存放着的是正常的page?还是swap-out后留下的swap_entry?
如果是swap_entry,那么slot上的值将被加上RADIX_TREE_EXCEPTIONAL_ENTRY标记(值为2)。swap_entry的值被左移两位后OR上RADIX_TREE_EXCEPTIONAL_ENTRY,填入slot。
也就是说,如果${slot}&RADIX_TREE_EXCEPTIONAL_ENTRY!=0,则它代表swap_entry,且swap_entry的值是${slot}>>2;否则它代表page,${slot}就是指向page的指针,当然其值可能是NULL,说明page尚未分配。
那么显然,page的地址值其末两位肯定是0,否则就可能跟RADIX_TREE_EXCEPTIONAL_ENTRY标记冲突了;而swap_entry的值最大只能是30bit或62bit(对应32位或64位机器),否则左移两位就溢出了。

最后以一张图说明一下匿名page、文件映射page、tmpfs/shmempage的回收及恢复过程:

J. Linux进程间如何共享内存

创建共享内存 shmget()
映射共享内存 shmat()
(使用映射的内存)
解除映射. shmdt()
删除共享内存 shmctl()

阅读全文

与linux设置共享内存相关的资料

热点内容
北京文件夹加密多少钱 浏览:669
什么是车鉴定app 浏览:64
战地一私人服务器怎么买 浏览:497
陈天程序员 浏览:833
编译原理如何运用到编程中 浏览:17
linux选择数据库 浏览:376
php两个数组差集 浏览:978
迷你pdf阅读器下载 浏览:433
做一个python小程序 浏览:655
pythonossystem和 浏览:645
win2008如何搭建ftp服务器 浏览:53
安卓手机为什么不翻牌 浏览:546
删除pkpm及相关文件夹 浏览:481
房贷解压银行内部流程 浏览:734
安卓手机如何更改语音 浏览:601
android红包实现 浏览:734
苹果的nvme为什么安卓不用 浏览:32
python输入单词统计个数 浏览:998
脚本软件提取源码 浏览:281
程序员能给自己的微信钱包刷钱么 浏览:73