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; } |
联系客服