共享内存

共享内存一般用在进程间共享比较大的数据的场景。如果是使用消息队列或者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 ",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 ",errno,strerror(errno));
  }

  printf("share mem:0x%x ", (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 ", errno, strerror(errno));
  }
  mem = mmap(NULL, sizeof(ShareMem), PROT_READ, MAP_SHARED, fd, 0);
  if (MAP_FAILED == mem)
  {
  printf("mmap fail: %d, %s ", errno, strerror(errno));
  }
  printf("share mem:0x%x,str:%s,val:%d ", (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
", errno);
        return -1;
    }
    gShm = shmat(shmId, (void*)0, 0);
    if ((void*)-1 == gShm)
    {
        printf("shmat fail:%d
", 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
");
        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
", 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
", 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
", 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
", 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
", 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 .

原文地址:https://www.cnblogs.com/fellow1988/p/6151378.html