`

linux c学习笔记----共享内存(shmget,shmat,shmdt,shmctl)

阅读更多

shmget
int shmget(key_t key, size_t size, int flag);
key: 标识符的规则
size:共享存储段的字节数
flag:读写的权限
返回值:成功返回共享存储的id,失败返回-1

key_t key
-----------------------------------------------
    key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。


    在IPC(InterProcess Communication)的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key)。通过“键”,进程能够识别所用的对象。“键”与IPC对象的关系就如同文件名称之于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够共用一个文件。而在IPC的通讯模式下,通过“键”的使用也使得一个IPC对象能为多个进程所共用。
    Linux系统中的所有表示System V中IPC对象的数据结构都包括一个ipc_perm结构,其中包含有IPC对象的键值,该键用于查找System V中IPC对象的引用标识符。如果不使用“键”,进程将无法存取IPC对象,因为IPC对象并不存在于进程本身使用的内存中。
    通常,都希望自己的程序能和其他的程序预先约定一个唯一的键值,但实际上并不是总可能的成行的,因为自己的程序无法为一块共享内存选择一个键值。因此,在此把key设为IPC_PRIVATE,这样,操作系统将忽略键,建立一个新的共享内存,指定一个键值,然后返回这块共享内存IPC标识符ID。而将这个新的共享内存的标识符ID告诉其他进程可以在建立共享内存后通过派生子进程,或写入文件或管道来实现。


int size(单位字节Byte)
-----------------------------------------------
    size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。所以如果一段进程只申请一块只有一个字节的内存,内存也会分配整整一页(在i386机器中一页的缺省大小PACE_SIZE=4096字节)这样,新创建的共享内存的大小实际上是从size这个参数调整而来的页面大小。即如果size为1至4096,则实际申请到的共享内存大小为4K(一页);4097到8192,则实际申请到的共享内存大小为8K(两页),依此类推。


int shmflg
-----------------------------------------------
    shmflg主要和一些标志有关。其中有效的包括IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。
    IPC_CREAT   如果共享内存不存在,则创建一个共享内存,否则打开操作
    IPC_EXCL    只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误

    如果单独使用IPC_CREAT,shmget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。如果将IPC_CREAT和IPC_EXCL标志一起使用,shmget()将返回一个新建的共享内存的标识符;如果该共享内存已存在,或者返回-1。IPC_EXEL标志本身并没有太大的意义,但是和IPC_CREAT标志一起使用可以用来保证所得的对象是新建的,而不是打开已有的对象。对于用户的读取和写入许可指定SHM_R和SHM_W,(SHM_R>3)和(SHM_W>3)是一组读取和写入许可,而(SHM_R>6)和(SHM_W>6)是全局读取和写入许可。

需要注意的是,使用参数要加上 | 0666 作为校验,在有些Linux系统中,如果不加此校验,则不能顺利获取共享空间的值(如Ubuntu)。此外,有两个常用参数,一般要同时出现,他们是:S_IRUSH | S_IWUSR 。由于这两个参数非常常用,程序员一般做这样的操作
  #define PERM S_IRUSR | S_IWUSR | IPC_CREAT
  这样一来,第三个参数就可以直接用PERM来表示了!

返回值
-----------------------------------------------
成功返回共享内存的标识符;不成功返回-1,errno储存错误原因。
    EINVAL        参数size小于SHMMIN或大于SHMMAX。
    EEXIST        预建立key所致的共享内存,但已经存在。
    EIDRM         参数key所致的共享内存已经删除。
    ENOSPC        超过了系统允许建立的共享内存的最大值(SHMALL )。
    ENOENT        参数key所指的共享内存不存在,参数shmflg也未设IPC_CREAT位。
    EACCES        没有权限。
    ENOMEM        核心内存不足。


struct shmid_ds
-----------------------------------------------
    shmid_ds数据结构表示每个新建的共享内存。当shmget()创建了一块新的共享内存后,返回一个可以用于引用该共享内存的shmid_ds数据结构的标识符。

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 */ 
        __kernel_time_t    shm_dtime;     /* last detach time */ 
        __kernel_time_t    shm_ctime;     /* last change time */ 
        __kernel_ipc_pid_t shm_cpid;      /* pid of creator */ 
        __kernel_ipc_pid_t shm_lpid;      /* pid of last operator */ 
        unsigned short     shm_nattch;    /* no. of current attaches */ 
        unsigned short     shm_unused;    /* compatibility */ 
        void               *shm_unused2; /* ditto - used by DIPC */ 
        void               *shm_unused3; /* unused */ 
    };


struct ipc_perm
-----------------------------------------------
    对于每个IPC对象,系统共用一个struct ipc_perm的数据结构来存放权限信息,以确定一个ipc操作是否可以访问该IPC对象。

    struct ipc_perm { 
        __kernel_key_t   key; 
        __kernel_uid_t   uid; 
        __kernel_gid_t   gid; 
        __kernel_uid_t   cuid; 
        __kernel_gid_t   cgid; 
        __kernel_mode_t mode; 
        unsigned short   seq; 
};
//----------------------------------------

shmat
void *shmat(int shmid, const void *addr, int flag);
shmid:共享存储的id
addr:一般为0,表示连接到由内核选择的第一个可用地址上,否则,如果flag没有指定SHM_RND,则连接到addr所指定的地址上,如果flag为SHM_RND,则地址取整
flag:如前所述,一般为0
返回值:如果成功,返回共享存储段地址,出错返回-1
共享存储器的执行方式是将一个储存器区段标记为共用,这时各进程可以把这个区段映射到该进程本身的虚拟地址里。建立共享存储器可通过shmget系统调用,shmget执行后,核心程序就保留一块指定大小的空间,同时关于此共享存储器的一切数据,如区段的长度,区段的存取权,区段建立者的进程识别码等存入一个叫shmid_ds的结构。现在共享存储器虽然已经建立了,可是仍无法连上它,这时就须通过shmat系统调用得到一个指向共享存储器基址的指针,通过此指针,就可以如同于操作一般存储器似的取用共享存储器。shmdt进行相反的工作,用来脱离已连上的共享存储器。


shmdt
int shmdt(void *addr);
addr:共享存储段的地址,以前调用shmat时的返回值
shmdt将使相关shmid_ds结构中的shm_nattch计数器值减1

当一个进程不再需要共享内存段时,它将调用shmdt()系统调用取消这个段,但是,这并不是从内核真正地删除这个段,而是把相关shmid_ds结构的 shm_nattch域的值减1,当这个值为0时,内核才从物理上删除这个共享段


shmctl
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
shmid:共享存储段的id
cmd:一些命令

IPC_STAT 得到共享内存的状态
        IPC_SET 改变共享内存的状态
        IPC_RMID 删除共享内存 

IPC_RMID 命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生在最后一个进程离开这个共享段时。 

请注意,共享内存不会随着程序结束而自动消除,要么调用shmctl删除,要么自己用手敲命令去删除,否则永远留在系统中。

 

实例:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define PERM S_IRUSR|S_IWUSR

int main(int argc,char **argv){
	int shmid;
	char *p_addr,*c_addr;
	if(argc!=2){
		fprintf(stderr,"Usage:%s\n\a",argv[0]);
		exit(1);
	}

	if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1){
		fprintf(stderr,"Create Share Memory Error:%s\n\a",strerror(errno));
		exit(1);
	}

	if(fork()){
		p_addr=shmat(shmid,0,0);
		memset(p_addr,'\0',1024);
		strncpy(p_addr,argv[1],1024);
		exit(0);
	}else{
		c_addr=shmat(shmid,0,0);
		printf("Client get %s",c_addr);
		exit(0);
	}
}
 这个程序是父进程将参数写入到共享内存,然后子进程把内容读出来.最后我们要使用ip

crm 释放资源的.先用ipcs 找出ID 然后用ipcrm shm ID 删除.

 

 

 

 

分享到:
评论

相关推荐

    linux 共享内存浅析

    shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。 参数char *shmaddr是那块共享内存的起始地址。 成功时返回0。失败时返回-1。 shmdt( head ); // 禁止本进程使用这块内存 此外,还有一个用来控制...

    linux kernel 源码剖析 共享内存部分

    这是我剖的2.6.15版本的linux内核源码 共享内存部分源码 其中包括shmget shmmat shmdt shmctl函数的内核调用,以及内核创建共享内存的过程。

    操作系统《02-基于共享存储区的进程间通信的设计》

    ⑵ 使用系统调用:shmget(),shmat(),shmdt()和shmctl(),编制一长度为1K的信息的发送和接收的程序; ⑶ 分析程序,说明shmget(),shmat(),shmdt()和shmctl()分别在程序中起什么作用,并解释其各个参数的含义。 2....

    Linux /Unix 共享内存

    共享内存的使用,主要有以下几个API:ftok()、shmget()、shmat()、shmdt()及shmctl()。 1)用ftok()函数获得一个ID号. 应用说明: 在IPC中,我们经常用用key_t的值来创建或者打开信号量,共享内存和消息队列。 函数...

    linux进程之间的通讯综合实例.zip_Linux共享内存_TCP/IP_message_pipe/fifo_shm

    B与C使用共享内存来交互 步骤是:shmget-&gt;shmat-&gt;直接读写---&gt;shmdt shmctl(删除) 可以man C与D之间使用消息传递进行 msgget--&gt;msgrcv-&gt;msgsnd (注意这里的返回值判断发送正确与否 不是发送的...

    浙江理工大学操作系统实验2:进程通信报告

    (3) 使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。要求在父进程中生成一个30字节长的私有共享内存段。接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。调用...

    操作系统实验3.doc

    实验三 管道及共享内存 1. 实验目的 熟悉管道通信,了解管道内数据的读取与写入过程;...运行结束后可以用ctrl+c结束程序1的运行 5、编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序;要求

    共享存储区的通信方式

    linux系统的通信机构IPC中消息通信机制提供四个操纵共享存储区的系统调用: shmget()的主要功能是建立新的共享存储区或返回一个已存在的共享存储区描述字, shmat(shmid,addr,flag)的主要功能是将物理共享区附接到...

    libandroid-shmem:使用Ashmem在Android上进行System V共享内存仿真

    libandroid-shmem 在使用ashmem在Android上进行System V共享内存(shmget,shmat,shmdt和shmctl)仿真。 它创建的共享内存段将在创建过程销毁它们或死时自动销毁,这与System V共享内存行为不同。 基于先前工作。...

    电子科大操作系统实验课Linux通过管道实现进程间通信

    在Linux系统中使用系统调用fork()创建两个子进程,使用系统调用pipe()建立一个管道,两个子进程分别向管道各写一句话: Child process 1 is sending a message! Child process 2 is sending a message! 而父进程则...

    c-inter-process-communication-example

    此示例包含一个main.c文件,其中显示框通过fork函数以及通过shmget , shmat , shmdt和shmctl函数进行的共享内存访问将执行克隆到子进程中。 链接到linux函数文档: 生成并运行 此存储库已准备好进行编译,并...

    UnixProgramming

    共享内存shmget、shmat/shmdt、shmctl UNIX域套接字socketpair/socket,socket 信号kill 线程 线程模型:内核线程、用户线程、双层调度 线程API 创建pthread_create 初始化pthread_once 结束pthread_exit 回收...

    操作系统实验4-4实验报告.docx

    操作系统实验报告 实验4-4: Linux共享存储通信 实验目的 (1) 掌握Linux提供的共享存储区通信方式的使用方法。 (2) 了解共享存储区通信方法的特点。 (3) 了解实现进程间通信的不同方法之间的区别、特点和适用情况。 ...

    Linux程序设计 第4版.haozip01

    第14章 信号量、共享内存和消息队列 488 14.1 信号量 488 14.1.1 信号量的定义 489 14.1.2 一个理论性的例子 489 14.1.3 linux的信号量机制 490 14.1.4 使用信号量 492 14.2 共享内存 496 14.2.1 shmget函数 ...

    Linux程序设计 第4版.haozip02

    第14章 信号量、共享内存和消息队列 488 14.1 信号量 488 14.1.1 信号量的定义 489 14.1.2 一个理论性的例子 489 14.1.3 linux的信号量机制 490 14.1.4 使用信号量 492 14.2 共享内存 496 14.2.1 shmget函数 ...

    Linux高性能服务器编程

    13.5.1 信号量原语 13.5.2 semget系统调用 13.5.3 semop系统调用 13.5.4 semctl系统调用 13.5.5 特殊键值IPC_PRIVATE 13.6 共享内存 13.6.1 shmget系统调用 13.6.2 shmat和shmdt系统调用 13.6.3 shmctl系统...

    UNIX网络编程 卷2 进程间通信 带完整书签,完整目录

    第14章 System V共享内存区 276 14.1 概述 276 14.2 shmget函数 276 14.3 shmat函数 277 14.4 shmdt函数 277 14.5 shmctl函数 277 14.6 简单的程序 278 14.7 共享内存区限制 281 14.8 小结 282 习题 283 ...

    UNIX网络编程 卷2:进程间通信

     第14章 System V共享内存区 276  14.1 概述 276  14.2 shmget函数 276  14.3 shmat函数 277  14.4 shmdt函数 277  14.5 shmctl函数 277  14.6 简单的程序 278  14.7 共享内存区限制 281  14.8 小结 282  ...

    《UNIX网络编程 第2版. 第2卷, 进程间通信(中文版)》(W·Richard Stevens[美] 著)

    本书全面深入地讲解了各种进程间通信形式,包括消息传递、同步、共享内存及远程调用(RPC)。书中包含了大量经过优化的源代码,帮助读者加深理解。这些源代码可以从图灵网站本书网页免费注册下载。本书是网络研究和...

    UNIX网络编程 第2卷 进程间通信

    本书全面深入地讲解了各种进程间通信形式,包括消息传递、同步、共享内存及远程调用(RPC)。书中包含了大量经过优化的源代码,帮助读者加深理解。这些源代码可以从图灵网站本书网页免费注册下载。 本书是网络研究和...

Global site tag (gtag.js) - Google Analytics