共享内存
共享内存一般用在进程间共享比较大的数据的场景。如果是使用消息队列或者socket在进程间发送大数据时,效率比较低下。
共享内存比较关键的点就是要处理好进程间的同步,即不允许别的进程访问正在修改的数据。同步可以用信号量来实现。
进程A创建共享内存,并往共享内存里面写数据。
mmap_write.c
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct _ShareMem{
char str[128];
int val;
}ShareMem;
#define SHM_STR "FELLOW_SHARE_SOMETHING"
void main(void)
{
int fd;
ShareMem *mem;
fd = shm_open(SHM_STR, O_RDWR | O_CREAT, 0666);
if (-1 == fd)
{
printf("shm_open fail:%d,%s\n",errno,strerror(errno));
}
ftruncate(fd, sizeof(ShareMem));//如果不调用ftruncate,会出现bus error
mem = mmap(NULL, sizeof(ShareMem), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mem == MAP_FAILED)
{
printf("mmap fail:%d,%s\n",errno,strerror(errno));
}
printf("share mem:0x%x\n", (int)mem);
strncpy(mem->str, "fellow", strlen("fellow"));
mem->val = 10000;
close(fd);
}
进程B读出共享内存的内容:
mmap_read.c
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
typedef struct _ShareMem{
char str[128];
int val;
}ShareMem;
#define SHM_STR "FELLOW_SHARE_SOMETHING"
void main(void)
{
int fd;
ShareMem *mem;
fd = shm_open(SHM_STR, O_RDONLY, 0666);
if (-1 == fd)
{
printf("shm_open fail: %d, %s\n", errno, strerror(errno));
}
mem = mmap(NULL, sizeof(ShareMem), PROT_READ, MAP_SHARED, fd, 0);
if (MAP_FAILED == mem)
{
printf("mmap fail: %d, %s\n", errno, strerror(errno));
}
printf("share mem:0x%x,str:%s,val:%d\n", (int)mem, mem->str, mem->val);
close(fd);
munmap(mem, sizeof(ShareMem));
shm_unlink(SHM_STR);
}
运行mmap_write后,结果如下:
ls -l /dev/shm/可以看到创建的共享内存:
运行mmap_read,结果如下:
shm.h:
#include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <pthread.h> #define MAX_SHM_SIZE 2048 typedef struct { unsigned int wp; unsigned int rp; unsigned int shmDataSize; pthread_mutex_t mutex; pthread_cond_t writeCond; char pData[MAX_SHM_SIZE]; }SHM_T; extern int shm_init(char *pathName, int projId, unsigned int size, unsigned char fgInit); extern int shm_write(char *pData, unsigned int size); extern int shm_write(char *pData, unsigned int size); extern int shm_uninit(int shmId); extern int shm_getAvailSize(unsigned char fgRead);
shm.c
#include "shm.h" SHM_T *gShm = NULL; int shm_init(char *pathName, int projId, unsigned int size, unsigned char fgInit) { int shmId; if (size > MAX_SHM_SIZE) return -1; key_t key = ftok(pathName, projId); shmId = shmget(key, sizeof(SHM_T), 0666 | IPC_CREAT); if (shmId == -1) { printf("shmget fail:%d\n", errno); return -1; } gShm = shmat(shmId, (void*)0, 0); if ((void*)-1 == gShm) { printf("shmat fail:%d\n", errno); } if (fgInit) { pthread_mutexattr_t mutexAttr; pthread_condattr_t condAttr; gShm->wp = gShm->rp = 0; memset(gShm->pData, 0, size); gShm->shmDataSize = size; pthread_mutexattr_init(&mutexAttr); pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED); pthread_mutex_init(&gShm->mutex, &mutexAttr); pthread_condattr_init(&condAttr); pthread_condattr_setpshared(&condAttr, PTHREAD_PROCESS_SHARED); pthread_cond_init(&gShm->writeCond, &condAttr); } return shmId; } int shm_write(char *pData, unsigned int size) { if (size >= gShm->shmDataSize) { printf("write fail, invalid size\n"); return -1; } pthread_mutex_lock(&gShm->mutex); unsigned int wp = gShm->wp; unsigned int rp = gShm->rp; unsigned int shmDataSize = gShm->shmDataSize; unsigned int remainWriteSize = shmDataSize - (wp - rp + shmDataSize) % shmDataSize - 1; while (size > remainWriteSize) { printf("no more space to write, wp:%d, rp:%d, write size:%d, remainWriteSize:%d\n", wp, rp, size, remainWriteSize); pthread_cond_wait(&gShm->writeCond, &gShm->mutex); wp = gShm->wp; rp = gShm->rp; remainWriteSize = shmDataSize - (wp - rp + shmDataSize) % shmDataSize - 1; } if (wp + size < shmDataSize) { memcpy(gShm->pData + wp, pData, size); } else { memcpy(gShm->pData + wp, pData, shmDataSize - wp); memcpy(gShm->pData, pData + shmDataSize - wp, size - (shmDataSize - wp)); } wp = (wp + size) % shmDataSize; gShm->wp = wp; pthread_mutex_unlock(&gShm->mutex); remainWriteSize = shmDataSize - (wp - rp + shmDataSize) % shmDataSize - 1; printf("write %s, wp:%d, rp:%d, remainWriteSize:%d\n", pData, wp, rp, remainWriteSize); return 0; } int shm_read(char *pData, unsigned int size) { pthread_mutex_lock(&gShm->mutex); unsigned int wp = gShm->wp; unsigned int rp = gShm->rp; unsigned int shmDataSize = gShm->shmDataSize; unsigned int remainReadSize = (wp - rp + shmDataSize) % shmDataSize; if (size > remainReadSize) { printf("no more data to read, wp:%d, rp:%d, read size:%d, remainReadSize:%d\n", wp, rp, size, remainReadSize); pthread_mutex_unlock(&gShm->mutex); return -1; } if (rp + size < shmDataSize) { memcpy(pData, gShm->pData + rp, size); } else { memcpy(pData, gShm->pData + rp, shmDataSize - rp); memcpy(pData + shmDataSize - rp, gShm->pData, size - (shmDataSize - rp)); } rp = (rp + size) % shmDataSize; gShm->rp = rp; pthread_cond_signal(&gShm->writeCond); pthread_mutex_unlock(&gShm->mutex); remainReadSize = (wp - rp + shmDataSize) % shmDataSize; printf("read %s, wp:%d, rp:%d, remainReadSize:%d\n", pData, wp, rp, remainReadSize); return 0; } int shm_uninit(int shmId) { if (0 == gShm) return -1; pthread_mutex_lock(&gShm->mutex); gShm->wp = gShm->rp = 0; gShm->shmDataSize = 0; pthread_mutex_unlock(&gShm->mutex); pthread_mutex_destroy(&gShm->mutex); pthread_cond_destroy(&gShm->writeCond); if (shmdt(gShm) == -1) { printf("shmdt fail:%d\n", errno); return -1; } shmctl(shmId, IPC_RMID, NULL) ; return 0; } int shm_getAvailSize(unsigned char fgRead) { pthread_mutex_lock(&gShm->mutex); unsigned int wp = gShm->wp; unsigned int rp = gShm->rp; unsigned int shmDataSize = gShm->shmDataSize; unsigned int availSize = 0; if (0 == fgRead) { availSize = shmDataSize - (wp - rp + shmDataSize) % shmDataSize - 1; } else if ( 1 == fgRead) { availSize = (wp - rp + shmDataSize) % shmDataSize; } pthread_mutex_unlock(&gShm->mutex); return availSize; }
shm_w.c:
#include "shm.h" #define STR_SIZE 1024 void main() { unsigned char fgRun = 1; unsigned int shmSize = 0; printf("Please input the shm size(<2048) you want to creat:"); scanf("%d", &shmSize); int shmId = shm_init("/tmp", 1, shmSize, 1); char str[STR_SIZE]; while (fgRun) { printf("please input the string you want to write:"); scanf("%s", str); shm_write(str, strlen(str)); if (0 == strncmp(str, "end", 3)) fgRun = 0; sleep(1); } shm_uninit(shmId); }
shm_r.c:
#include "shm.h" #define STR_SIZE 1024 void main() { unsigned char fgRun = 1; unsigned int shmSize = 0; shm_init("/tmp", 1, shmSize, 0); char str[STR_SIZE]; int len = 0; while (fgRun) { printf("please input the string len you want to read:"); scanf("%d", &len); if (-1 == len) { fgRun = 0; break; } memset(str, 0, STR_SIZE); shm_read(str, len); sleep(1); } }
gcc -shared -fPIC shm.c -o libshm.so -lpthread -I .
gcc shm_r.c -o shm_r -L . -lshm -Wl,-rpath . -I .
gcc shm_w.c -o shm_w -L . -lshm -Wl,-rpath . -I .