打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
UNP共享内存
UNP--POSIX共享内存
2010-09-23 10:18
POSIX提供了2种共享内存的方式:
1.内存映射文件:由open打开,由mmap函数把得到的描述符映射到当前进程地址空间
2.共享内存对象:由shm_open打开一个IPC名字,所返回的描述字由mmap映射到当前进程的地址空间

需要包含的头文件

<sys/types.h>
<sys/mman.h>
<fcntl.h>
编译加 -lrt

创建或者打开共享内存对象

int shm_open(const char *name, int oflag, mode_t mode);
成功返回非负的文件描述符;失败返回-1,设置errno
oflag:必须指定为O_RDONLY或者O_RDWR,其他值:O_CREAT, O_EXCL, O_TRUNC
如果设置O_TRUNC,将截断为0长度
mode:必须指定的,可以设置为0
新创建的共享内存的长度为0

删除共享内存对象

int shm_unlink(const char *name);
成功返回0;失败返回-1,设置errno

设置共享内存的大小

int ftruncate(int fd, off_t length);
成功返回0;失败返回-1,设置errno
共享内存被扩展时,其扩展部分的内容自动初始化为0
查看共享内存的状态
int fstat(int fd, struct stat *buf);
成功返回0;失败返回-1,设置errno

// 创建、读写、删除共享内存

int main(int argc, char *argv[])
{
int i, fd, flags;
unsigned char *ptr, c;
off_t length;
struct stat stat;
flags = O_RDWR|O_CREAT;
if (argc !=3) {
printf("usage: shm name length\n");
exit(1);
}
length = atoi(argv[2]);
fd = shm_open(argv[1], flags, 0644);
ftruncate(fd, length);
fstat(fd, &stat);
ptr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
// 写共享内存
for (i = 0; i < stat.st_size; i++)
*ptr++ = i%256;
// 读共享内存
for (i = 0; i < stat.st_size; i++)
if ((c = *ptr++) != (i%256))
printf("error\n");
shm_unlink(argv[1]); // 删除共享内存
return 0;
}

// 同一共享内存映射到不同的进程空间时,起始地址可以不同

int main(int argc, char *argv[])
{
int fd1, fd2, *ptr1, *ptr2;
pid_t pid;
struct stat stat;
assert(2 == argc);
fd1 = shm_open(argv[1], O_RDWR|O_CREAT|O_EXCL, 0644);
ftruncate(fd1, sizeof(int));
fd2 = open("/etc/bashrc", O_RDONLY);
fstat(fd2, &stat);
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
else if (0 == pid) {
ptr2 = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd2, 0);
ptr1 = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
printf("child:  ptr1=%p, ptr2=%p\n", ptr1, ptr2);
sleep(5);
printf("shared mem integer: %d\n", *ptr1);
_exit(0);
}
else {
ptr1 = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
ptr2 = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd2, 0);
printf("parent: ptr1=%p, ptr2=%p\n", ptr1, ptr2);
*ptr1 = 777;
waitpid(pid, NUL, 0);
exit(0);
}
}
输出如下:
child:  ptr1=0xb7eff000, ptr2=0xb7f00000
parent: ptr1=0xb7f00000, ptr2=0xb7eff000
shared mem integer: 777

// 多个客户进程同时给一个计数器加1

// shm_serv.c
int count;
sem_t *sem;
int main(int argc, char *argv[])
{
int fd;
int *ptr;
if (argc != 3) {
printf("usage: serv <shm_name> <sem_name>\n");
exit(1);
}
fd = shm_open(argv[1], O_RDWR|O_CREAT|O_EXCL, 0644);
ftruncate(fd, sizeof(int));
ptr = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
sem = sem_open(argv[2], O_CREAT|O_EXCL, 0644, 1);
sem_close(sem);
return 0;
}
// shm_cli.c
int count;
sem_t *sem;
int main(int argc, char *argv[])
{
int fd, i, loop;
pid_t pid;
int *ptr;
if (argc != 4) {
printf("usage: cli <shm_name> <sem_name> <#loops>");
exit(1);
}
loop = atoi(argv[3]);
fd = shm_open(argv[1], O_RDWR, 0644);
ptr = mmap(NULL, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
sem = sem_open(argv[2], 0);
pid = getpid();
for (i=0; i<loop; i++) {
sem_wait(sem);
printf("pid=%ld: %d\n", (long)pid, (*ptr)++);
sem_post(sem);
}
return 0;
}

// 多个客户通过共享内存向服务器发送消息

//N生产者--1消费者
// 公共头文件 data.h
#define MSGSIZE 1024 /* 消息的最大size */
#define NMSG 8 /* 最大消息数量 */
typedef struct {
sem_t sem;
sem_t nempty;
sem_t nstored;
int nput;
long noverflows;
sem_t overflow;
long offset[NMSG]; /* 存放每个消息的偏移量 */
char data[NMSG*MSGSIZE];
} shared;

// 服务器程序

int main(int argc, char *argv[])
{
int fd, index, last_overflow, temp;
long offset;
shared *ptr;
if (argc != 2) {
printf("usage: server <shm_name>");
exit(1);
}
fd = shm_open(argv[1], O_RDWR|O_CREAT|O_EXCL, 0644);
ptr = mmap(NULL, sizeof(shared), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
ftruncate(fd, sizeof(shared));
close(fd);
for (index=0; index<NMSG; index++)
ptr->offset[index] = index * MSGSIZE;
sem_init(&ptr->sem, 1, 1);
sem_init(&ptr->nempty, 1, NMSG);
sem_init(&ptr->nstored, 1, 0);
sem_init(&ptr->overflow, 1, 1);

index = 0;

last_overflow = 0;
for ( ; ; ) {
sem_wait(&ptr->nstored);
sem_wait(&ptr->sem);
offset = ptr->offset[index];
printf("index=%d: %s\n", index, &ptr->data[offset]);
if (++index >= NMSG)
index = 0;
sem_post(&ptr->sem);
sem_post(&ptr->nempty);

sem_wait(&ptr->overflow);

temp = ptr->noverflows;
sem_post(&ptr->overflow);
if (temp != last_overflow) {
printf("noverflows=%d\n", temp);
last_overflow = temp;
}
}   
return 0;
}

// 客户程序

int main(int argc, char *argv[])
{
int fd, i, loop, us;
pid_t pid;
char msg[MSGSIZE];
long offset;
shared *ptr;
if (argc != 4) {
printf("usage: client <shm_name> <#loops> <#usec>");
exit(1);
}
loop = atoi(argv[2]);
us = atoi(argv[3]);
fd = shm_open(argv[1], O_RDWR, 0644);
ptr = mmap(NULL, sizeof(shared), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);   
pid = getpid();
for (i=0; i<loop; i++) {
usleep(us);
snprintf(msg, MSGSIZE, "pid %ld: message %d", (long)pid, i);
if (sem_trywait(&ptr->nempty) == -1) {
if (errno == EAGAIN) {
sem_wait(&ptr->overflow);
ptr->noverflows++;
sem_post(&ptr->overflow);
continue;
}
else {
perror("sem_trywait");
exit(1);
}
}
sem_wait(&ptr->sem);
offset = ptr->offset[ptr->nput];
if (++(ptr->nput) >= NMSG)
ptr->nput = 0;
sem_post(&ptr->sem);
strcpy(&ptr->data[offset], msg);
sem_post(&ptr->nstored);
}
return 0;
}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Linux进程通信之POSIX共享内存
Linux 共享内存(POSIX)
Android逆向工程
mmap()
Linux编程日日练
mmap把文件映射到内存
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服