zoukankan      html  css  js  c++  java
  • 共享内存

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

  • 相关阅读:
    Netscape中使用event对象
    attachEvent 与 addEventListener 对同一物件事件多次绑定的触发顺序
    ADO.NET Entity Framework如何:定义具有修改存储过程的模型(实体框架)
    ADO.NET Entity Framework插入和更新数据(实体框架快速入门)
    ADO.NET Entity Framework如何:通过每种类型一个表继承以定义模型(实体框架)
    ADO.NET Entity Framework SSDL 规范
    ADO.NET Entity Framework 如何:使用 EdmGen.exe 生成对象层代码
    ADO.NET Entity Framework CSDL、SSDL 和 MSL 规范
    ADO.NET Entity Framework MSL 规范
    ADO.NET Entity Framework配置实体框架(实体框架任务)
  • 原文地址:https://www.cnblogs.com/fellow1988/p/6151378.html
Copyright © 2011-2022 走看看