linux進程間通信之Posix共享內存用法詳解及代碼舉例
Posix共享內存有兩種非親緣進程間的共享內存方法:
1). 使用內存映射文件,由open函數打開,再由mmap函數把返回的文件描述符映射到當前進程空間中的一個文件。
2). 使用共享內存區對象,由shm_open打開一個 Posix IPC名字。再由mmap把返回的描述符映射到當前進程的地址空間。
Posix共享內存相關函數頭文件及原型:
#include <sys/mman.h>
int shm_open(const char *name, int oflag, mode_t mode);
功能:打開一個共享內存對象,獲取描述符
返回值:成功返回非負描述符,出錯返回-1
參數:name是Posix IPC名字;oflag參數為O_RDONLY或O_RDWR,還可以為O_CREAT,O_EXCL,O_TRUNC,當在共享內存對象已存在的情況下指定O_RDWR和O_TRUNC會被截短為長度0;mode是指定權限位,在有O_CREAT指定的情況下使用,沒有O_CREAT時也要必須設為0。
int shm_unlink(const char *name);
功能:刪除一個共享內存區對象的名字。
返回值: 成功返回0,出錯返回-1.
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
功能:把由shm_open打開的共享內存對象映射到進程地址空間。
返回值:若成功則返回映射區的起始地址,出錯返回MAP_FAILED。
參數: addr指定被映射到的進程空間的起始地址,一般設為空指針NULL,表示自動分配;len是映射到地址空間的字節數,從文件頭開始第offset個字節開始算,一般offset設置為0;prot可以為PROT_READ(可讀),PROT_WRITE(可寫),PROT_EXEC(可執行),PROT_NONE(不可訪問);flags可以為MAP_SHARED,MAP_PRIVATE,MAP_FIXED,其中MAP_SHARED或MAP_PRIVATE必須指定一個,MAP_FIXED一般不指定並且addr為空指針,表示自動分配地址,方便移植。
int munmap(void *addr, size_t len);
功能:刪除進程地址空間的映射關系
返回值:成功返回0,出錯返回-1
int msync(void *addr, size_t len, int flags);
功能:是文件內容與內存映射區中內容一致。
返回值: 成功返回0,出錯返回-1.
參數: flags有3種,MS_ASYNC(異步寫),MS_SYNC(同步寫),MS_INVALIDATE(使緩存的數據失效)。
代碼舉例shm_test.c,父子進程操作共享內存區變量計數加1,並且用信號量sem做同步
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/mman.h>
- #include <semaphore.h>
- #include <fcntl.h>
- #define MYFILE "./shm_test_file"
- #define SEM_NAME "/mysem"
- #define MYSHM "/myshm"
- #define TIMES 5
- #define USE_SHM_OPEN 0
- #define SEM_IN_SHAREMEMORY 0
- #if SEM_IN_SHAREMEMORY
- struct shared
- {
- sem_t mutex;
- int count;
- }shared;
- #endif
- int main(void)
- {
- int fd,i,zero=0;
- #if SEM_IN_SHAREMEMORY
- struct shared *ptr;
- #if USE_SHM_OPEN
- fd=shm_open(MYSHM,O_RDWR|O_CREAT,0666);
- #else
- fd=open(MYFILE,O_RDWR|O_CREAT,0666);
- #endif
- write(fd,&shared,sizeof(struct shared));
- ptr=mmap(NULL,sizeof(struct shared),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
- sem_init(&ptr->mutex,1,1);
- #else
- int *ptr;
- sem_t *mutex;
- #if USE_SHM_OPEN
- fd=shm_open(MYSHM,O_RDWR|O_CREAT,0666);
- #else
- fd=open(MYFILE,O_RDWR|O_CREAT,0666);
- #endif
- write(fd,&zero,sizeof(int));
- ptr=mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
- mutex=sem_open(SEM_NAME,O_CREAT|O_EXCL,0666,1);
- sem_unlink(SEM_NAME);
- #endif
- close(fd);
- setbuf(stdout,NULL);//stdout is unbuffered
- if(0==fork())
- {
- for(i=0;i<TIMES;i++)
- {
- #if SEM_IN_SHAREMEMORY
- sem_wait(&ptr->mutex);
- printf("child : %d\n",ptr->count++);
- sem_post(&ptr->mutex);
- #else
- sem_wait(mutex);
- printf("child : %d\n",(*ptr)++);
- sem_post(mutex);
- #endif
- }
- exit(0);
- }
- for(i=0;i<TIMES;i++)
- {
- #if SEM_IN_SHAREMEMORY
- sem_wait(&ptr->mutex);
- printf("parent : %d\n",ptr->count++);
- sem_post(&ptr->mutex);
- #else
- sem_wait(mutex);
- printf("parent : %d\n",(*ptr)++);
- sem_post(mutex);
- #endif
- }
- exit(0);
- }
運行結果:
./a.out
parent : 0
parent : 1
parent : 2
parent : 3
parent : 4
child : 5
child : 6
child : 7
child : 8
child : 9
通過設置“#define USE_SHM_OPEN 1”使用共享內存對象映射,“#define USE_SHM_OPEN 0” 使用不同文件系統映射。
設置“#define SEM_IN_SHAREMEMORY 1”使信號量SEM也放在共享內存區,“#define SEM_IN_SHAREMEMORY 0”使信號量SEM不在共享內存區
linux進程間通信之Posix共享內存用法詳解及代碼舉例