POSIX 共享内存能够让无关进程共享一个映射区域而无需创建一个相应的映射文件,Linux 内核从 2.4 起开始支持 POSIX 共享内存。Linux 使用挂载于 /dev/shm
目录下的专用 tmpfs
文件系统,这个文件系统具有内核持久性——它所包含的共享内存对象会一直持久,即使当前不存在任何进程打开它,但这些对象会在系统关闭后丢失。
文章目录
编译步骤,需要链接 -lrt
,比如:sudo gcc pshm_create.c -o pshm_create -lrt
创建
int shm_open(const char *name, int oflag, mode_t mode);
name 参数标识出了待创建或待打开的共享内存对象;oflag 参数是一个改变调用行为的位掩码;mode参数与该内存对象的所有权和组所有权有关,mode参数能取的位值与文件上的权限位值是一样的。
oflag:
O_CREAT
对象不存在时创建对象O_EXCL
与O_CREAT
互斥地创建对象,如果O_CREAT
也被设置,能够确保调用者是对象的创建者,如果对象已经存在,那么就返回一个错误O_RDONLY
打开只读访问O_RDWR
打开读写访问O_TRUNC
将对象长度截断为 0
如果 oflag 参数中不包含 O_CREAT
,那么就打开一个既有对象,如果指定了 O_CREAT
,那么就在对象不存在时创建对象。
// POSIX share mem
// sudo gcc pshm_create.c -o pshm_create -lrt
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <getopt.h>
// int shm_open(const char *name, int oflag, mode_t mode);
static void usageError(const char *progName)
{
fprintf(stderr, "Usage: %s [-cx] name size [octal-perms]\n", progName);
fprintf(stderr, "\t-c Create sharedmemory (O_CREAT)\n");
fprintf(stderr, "\t-x Create exclusively (O_EXCL)\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int flags, opt, fd;
mode_t perms;
long long int size; // size_t size;
void *addr;
flags = O_RDWR;
while((opt = getopt(argc, argv, "cx")) != -1)
{
switch(opt)
{
case 'c': flags |= O_CREAT; break;
case 'x': flags |= O_EXCL; break;
default: usageError(argv[0]);
}
}
// printf("argc=%d, optind=%d\n", argc, optind);
if(optind + 1 >= argc)
usageError(argv[0]);
size = atol(argv[optind+1]);
perms = S_IRUSR | S_IWUSR;
// printf("%lld\n", size);
// create shared memory object and set its size
fd = shm_open(argv[optind], flags, perms);
if(fd == -1)
exit(EXIT_FAILURE);
if(ftruncate(fd, size) == -1)
exit(EXIT_FAILURE);
// map shared memory object
addr = mmap(NULL,size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
创建一个长度 1000 字节的共享内存对象,然后在 /dev/shm
中使用 ls
命令显出了这个对象。
写入
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <getopt.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd;
long long int len; // size of shared memory object
char *addr;
if(argc != 3 || strcmp(argv[1], "--help") == 0)
{
printf("%s shm-name string\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = shm_open(argv[1], O_RDWR, 0); // open
if(fd == -1)
exit(EXIT_FAILURE);
len = strlen(argv[2]);
if(ftruncate(fd, len) == -1) // resize with strlen()
exit(EXIT_FAILURE);
printf("Resized to %ld bytes\n", (long)len);
addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED)
exit(EXIT_FAILURE);
if(close(fd) == -1)
exit(EXIT_FAILURE);
printf("copying %ld bytes\n", (long)len);
memcpy(addr, argv[2], len); // write to shm
exit(EXIT_SUCCESS);
}
向共享内存对象 demo_shm
写入字符 hello
。共享对象大小变为 5 的原因是 ftruncate()
系统调用根据写入内容的长度改变共享对象大小的缘故。
读出
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <getopt.h>
#include <string.h>
int main(int argc, char *argv[])
{
int fd;
char *addr;
struct stat sb;
if(argc != 2 || strcmp(argv[1], "--help") == 0)
{
printf("%s shm-name string\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = shm_open(argv[1], O_RDONLY, 0); // open
if(fd == -1)
exit(EXIT_FAILURE);
if(fstat(fd, &sb) == -1) // fstat 由文件描述词取得文件状态
exit(EXIT_FAILURE);
addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if(addr == MAP_FAILED)
exit(EXIT_FAILURE);
if(close(fd) == -1)
exit(EXIT_FAILURE);
write(STDOUT_FILENO, addr, sb.st_size);
printf("\n");
exit(EXIT_SUCCESS);
}
删除
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <getopt.h>
#include <string.h>
int main(int argc, char *argv[])
{
if(argc != 2 || strcmp(argv[1], "--help") == 0)
{
printf("%s shm-name string\n", argv[0]);
exit(EXIT_FAILURE);
}
if(shm_unlink(argv[1]) == -1)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
}
在其它程序中使用工具
#include <stdio.h>
#include <stdlib.h>
#define SHM_NAME "demo_shm"
#define CREATE_SCRIPT "pshm_unlink"
int main(int argc, char *argv[])
{
char cmd[50] = {0};
sprintf(cmd, "./%s %s ", CREATE_SCRIPT, SHM_NAME);
printf("%s\n", cmd);
system(cmd);
exit(0);
}