• Linux IPC System V 共享内存


    模型

    #include<sys/types.h>
    #include<sys/ipc.h>
    #include<sys/shm.h>
    ftok()	    //获取key值			
    shmget()    //创建/获取共享内存	
    shmat()     //挂接共享内存		
    shmdt()     //脱接共享内存		
    shmctl()    //删除共享内存		
    

    ftok()

    //获取key值, key值是System V IPC的标识符,成功返回key,失败返回-1设errno
    //同pathname+同 proj_id==>同key_t;
    key_t ftok(const char *pathname, int proj_id);
    

    pathname :文件名
    proj_id: 1~255的一个数,表示project_id

    key_t key=ftok(".",100);	//“.”就是一个存在且可访问的路径, 100是假设的proj_id
    	if(-1==key)
    		perror("ftok"),exit(-1);
    

    shmget()

    //创建/获取共享内存,成功返回共享内存的标识符shmid,失败返回-1设errno
    int shmget(key_t key, size_t size, int shmflg);		//多设为int shmid=...  和shmat()一起用比较好看
    

    key :ftok()的返回值
    size:共享内存的大小,实际会按照页的大小(PAGE_SIZE)来分配。0表示获取已经分配好的共享内存
    shmflg:具体的操作标志

    • IPC_CREAT:若不存在则创建, 需要在shmflg中"|权限信息", eg: |0664; 若存在则打开
    • IPC_EXCL:与IPC_CREAT搭配使用, 若存在则创建失败==>报错,set errno
    • 0 :获取已经存在的共享内存
    //创建shared memory
    shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0664);
    if(-1==shmid)
    	perror("shmget"),exit(-1);
    

    Q:既然shmget()可以创建, 那要ftok()有啥用
    A:shmget才是创建共享内存, ftok()只是用来产生一个key,其实这个key的位置自己随意填一个数也可以运行,但是相对系统生成的,很容易造成冲突,所以最好用ftok产生一个key

    shmat()

    //挂接共享内存,成功返回映射内存的地址,失败返回(void*)-1设errno
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    

    shmid: shmget()的返回值
    shmaddr

    • NULL表示由系统选择 (同mmap())
    • 非NULL且shflg是SHM_RND,会按照页对齐的原则从shmaddr开始找最近的地址开始分配分,否则shmaddr指定的地址必须是页对齐的
    • shmflg :操作的标志, 给0即可
      • SHM_RDONLY表示挂接到该共享内存的进程必须有读权限
      • SHM_REMAP (Linux-specific)表示如果要映射的共享内存已经有现存的内存,那么就将旧的替换
    //挂接共享内存
    void* pv=shmat(shmid,NULL,0);
    if((void*)-1==pv)
    	perror("shmat"),exit(-1);
    

    shmdt()

    //脱接共享内存,成功返回0,失败返回-1设errno
    int shmdt(const void *shmaddr);
    
    //脱接shm
    int res=shmdt(pv);
    if(-1==res)
    	perror("shmdt"),exit(-1);
    

    shmctl()

    //共享内存管理,成功返回0,失败返回-1设errno
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    

    shmid:共享内存的id,由shmget()返回
    buf : shmid_ds类型的指针

    struct shmid_ds {
       struct ipc_perm 	shm_perm;    	/* Ownership and permissions */
    	size_t			shm_segsz;   	/* Size of segment (bytes) */
    	time_t 			shm_atime;   	/* Last attach time */
    	time_t  		shm_dtime;   	/* Last detach time */
    	time_t    		shm_ctime;   	/* Last change time */
    	pid_t    		shm_cpid;    	/* PID of creator */
    	pid_t     		shm_lpid;    	/* PID of last shmat(2)/shmdt(2) */
    	shmatt_t		shm_nattch;  	/* No. of current attaches */
    	...
    };
    //<sys/ipc.h>
    struct ipc_perm {
       key_t			__key;  	/* Key supplied to shmget(2) */
       uid_t     		uid;      	/* Effective UID of owner */
       gid_t      		gid;      	/* Effective GID of owner */
       uid_t  			cuid;     	/* Effective UID of creator */
       gid_t			cgid;     	/* Effective GID of creator */
       unsigned short	mode;    	/* Permissions + SHM_DEST and SHM_LOCKED flags */
       unsigned short 	__seq;    	/* Sequence number */
    };
    

    cmd

    • IPC_STAT表示从内核中拷贝关于这个shmid的信息到buf指向的shmid_ds中
    • IPC_SET 将buf指向的shmid_ds的信息写入到内核的结构体中,同时更新成员shm_ctime
    • IPC_RMID销毁共享内存
    • IPC_INFO(Linux-specific)返回系统对共享内存的限制写入到buf指向的时shminfo结构体中
    //_GNU_SOURCE
    struct  shminfo {
    		unsigned long 	shmmax; /* Maximum segment size */
        	unsigned long 	shmmin; /* Minimum segment size; always 1 */
    		unsigned long 	shmmni; /* Maximum number of segments */
    		unsigned long 	shmseg; /* Maximum number of segments that a process can attach; unused within kernel */
    		unsigned long 	shmall; /* Maximum number of pages of shared memory, system-wide */
     };
     //shmmni, shmmax, and shmall 可以童工/proc里的同名文件进行修改
    
    • SHM_INFO(Linux-specific) 返回一个shm_info结构体来表示该共享内存消耗的系统资源
    //_GNU_SOURCE
    struct shm_info {
    		int           	used_ids; 	/* # of currently existing segments */
    	 	unsigned long 	shm_tot;  	/* Total number of shared memory pages */
    	  	unsigned long 	shm_rss;	/* # of resident shared memory pages */
    	    unsigned long 	shm_swp;  	/* # of swapped shared memory pages */
    	    unsigned long 	swap_attempts; /* Unused since Linux 2.4 */
    		unsigned long 	swap_successes;/* Unused since Linux 2.4 */
     };
    
    • SHM_STAT(Linux-specific) 为IPC_STAT返回一个shmid_ds结构结构体,不同的是shmid的参数不是一个标识符,而是内核中一个包含了系统中所有共享内存信息的索引
    • SHM_LOCK防止系统将共享内存放到swap区,IPC_STAT读到的信息中SHM_LOCKED标记就被设置了
    • SHM_UNLOCK 解除锁定,即允许共享内存被系统放到swap区
    //使用IPC_RMID删除共享内存
    int res=shmctl(shmid,IPC_RMID,NULL);
    if(-1==res)
    	perror("shmctl"),exit(-1);
    

    例子

    //Sys V IPC shm
    int shmid;			//定义全局变量记录id
    void fa(int signo){
    	printf("deleting shared memories...
    ");
    	sleep(3);//其实没用
    	int res=shmctl(shmid,IPC_RMID,NULL);
    	if(-1==res)
    		perror("shmctl"),exit(-1);
    	printf("delete success
    ");
    	exit(0);	//ctrl+C已经不能结束while(1),用exit(0)来终结
    }
    int main(){
    	//获取key
    	key_t key=ftok(".",100);	//.就是一个存在且可访问的路径, 100是随便给的
    	if(-1==key)
    		perror("ftok"),exit(-1);
    	printf("key=%#x
    ",key);	//打印出进制的标示,即0x
    	//创建shared memory
    	shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0664);
    	if(-1==shmid)
    		perror("shmget"),exit(-1);
    	printf("shmid=%d
    ",shmid);
    	//挂接shm
    	void* pv=shmat(shmid,NULL,0);
    	if((void*)-1==pv)
    		perror("shmat"),exit(-1);
    	printf("link shared memory success
    ");
    	//访问shm
    	int* pi=(int*)pv;
    	*pi=100;
    	//脱接shm
    	int res=shmdt(pv);
    	if(-1==res)
    		perror("shmdt"),exit(-1);
    	printf("unlink success
    ");
    	//如果不再使用,删除shm
    	printf("删除共享内存请按Ctrl C...
    ");
    	if(SIG_ERR==signal(SIGINT,fa))
    		perror("signal"),exit(-1);
    	while(1);
    	return 0;
    }
    
  • 相关阅读:
    [NC13331]城市网络
    Codeforces Round #638 (Div. 2)
    牛客练习赛62
    “科大讯飞杯”第18届上海大学程序设计联赛春季赛暨高校网络友谊赛
    Codeforces Round #635 (Div. 2)
    Codeforces Round #631 (Div. 2)
    牛客每日一题
    Codeforces Round #627 (Div. 3)
    MySQL查看建表语句
    Oracle的number数据类型
  • 原文地址:https://www.cnblogs.com/xiaojiang1025/p/5935662.html
Copyright © 2020-2023  润新知