Linux shmget/shmat/shmctl共享内存

来源:互联网 发布:淘宝怎么加入聚划算 编辑:程序博客网 时间:2024/05/22 03:26

标识符和键

每个内核中的IPC结构都用一个非负整数的标识符加以引用。无论何时创建IPC结构,都应指定一个。这个键的数据类型是基本系统数据类型key_t,通常在头文件< sys/types.h >中被定义为长整型。这个键由内核变换成标识符。


ftok创建键

#include <sys/ipc.h>key_t ftok(const char* path, int id);

path参数必须引用一个现有的文件。当产生键时,只使用id参数的低8位。
ftok函数的实现:

  • 通过path取得其stat结构的st_dev

  • 通过path取得其stat结构的st_ino

  • id的低序8位

在访问同一共享内存的多个进程先后调用ftok函数的时间段中,如果 path指定的文件被删除且重新创建,则文件系统会赋予这个同名文件新的inode节点信息,于是这些进程所调用的ftok虽然都能 正常返回,但得到的键值却并不能保证相同。


shmget函数

shget函数创建一个新的共享内存区,或者访问一个已存在的共享内存区。

#include <sys/shm.h>int shmget(key_t key, size_t size, int oflag);

返回值是一个称为共享内存区标识符的整数,其他三个shmXXX函数就用它来代指这个内存区。

  • key既可以是ftok的返回值,也可以是IPC_PRIVATE(创建一个新的IPC结构)

  • size以字节为单位指定内存区的大小,若是创建一个新的共享内存区则size不能为0,否则相反

  • oflag是读写权限值的组合,同open函数的0777权限值一般


shmat函数

连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问

#include <sys/shm.h>void *shmat(int shmid, const void* shaddr, int flag);
  • shmid为shmget函数成功返回的标识符

  • shaddr,指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置

  • flag读写权限值的组合

关于shaddr参数:

如果shmaddr是一个非空指针,那么返回地址取决于调用者是否给flag参数指定了SHM_RND值

  • 如果没有指定SHM_RND,那么相应的共享内存区附接到由shmaddr参数指定的地址

  • 如果指定SHM_RND,那么相应的共享内存区附接到由shmaddr参数指定的地址向下舍入一个SHMLBA常值。


shmctl函数

shmctl提供了对一个共享内存区的多钟操作

#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buff);
  • shmid共享内存标识符

  • cmd提供了三个命令

    • IPC_RMID 从系统中删除由shmid标识的共享内存区并拆除它
    • IPC_SET 给指定的共享内存区设置其shmid_ds结构的以下三个成员: shm_perm.uid、shm_perm.gid和shm_perm.mode,它们的值来自buff参数指向的结构中的相应成员。shm_ctime的值也用当前时间替换
    • IPC_STAT 通过buff参数向调用者返回指定共享内存区当前的shmid_ds结构
  • 共享内存管理结构体。


炒鸡简单示例

#include<stdio.h>#include<sys/shm.h>#include<unistd.h>                                          #include<string.h>#include<stdlib.h>                  #define SHM_SIZE 1024      int main()                        {                               // 创建共享内存对象                                  int shmid = shmget(IPC_PRIVATE, SHM_SIZE, 0777);                      // 获取共享内存指针          char* shmptr;              shmptr= shmat(shmid, 0, 0);                   strcpy(shmptr,"hello shm");                            printf("%s",shmptr);              // free                        shmctl(shmid, IPC_RMID, 0);            return 0;              }

非血缘进程共享映射区通信

server

#include<stdio.h>#include<sys/ipc.h>#include<unistd.h>#include<sys/shm.h>#include<string.h>int main(){    // 通过文件创建key    key_t mykey = ftok("test.txt",0x03);    if(mykey < 0)    {        printf("ftok err\n");        return -1;    }    // 获得标识符    int shmid = shmget(mykey,4096,IPC_CREAT|IPC_EXCL|0600);    if(shmid < 0)    {        printf("shmget err\n");        return -1;    }    // 获得指向共享内存的指针    char* shmptr = (char*)shmat(shmid, NULL, 0);    if(shmptr == NULL)    {        printf("shmat err\n");        return -1;    }    // 写入    const char* tmp = "hello salute";    strcpy(shmptr,tmp);    shmptr[strlen(tmp)] = '\0';    printf("wait\n");    getchar();    // 清空并断开    shmctl(shmid,IPC_RMID,0);    return 0;}

client

#include<stdio.h>#include<sys/ipc.h>#include<unistd.h>#include<sys/shm.h>#include<string.h>int main(){    // 通过文件创建key    key_t mykey = ftok("test.txt",0x03);    if(mykey < 0)    {        printf("ftok err\n");        return -1;    }    // 获得标识符    int shmid = shmget(mykey,4096,0600);    if(shmid < 0)    {        printf("shmget err\n");        return -1;    }    // 获得指向共享内存的指针    char* shmptr = (char*)shmat(shmid, NULL, 0);    if(shmptr == NULL)    {        printf("shmat err\n");        return -1;    }    printf("%s",shmptr);    return 0;}
0 0
原创粉丝点击