Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48486
  • 博文数量: 10
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 100
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-20 13:19
文章分类

全部博文(10)

文章存档

2016年(2)

2015年(8)

我的朋友

分类: LINUX

2015-04-19 23:15:54

用几个小程序简单总结一下UNPv2讲的三种内存共享的方法。

一、内存映射文件


(1)内存映射文件(可用在无亲缘关系的进程间共享)


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.   
  9. #define FILE_MODE       (S_IRWXU | S_IRWXG | S_IRWXO)  
  10. #define IPC_FILE        "/tmp/temp.1"  
  11.   
  12. int main(int argc, char **argv)  
  13. {  
  14.         int fd = -1, i, nloop, zero = 0;  
  15.         int *ptr;  
  16.         sem_t mutex;  
  17.   
  18.         if (argc != 2)  
  19.         {  
  20.                 printf("usage: incr \n");  
  21.                 return -1;  
  22.         }  
  23.   
  24.         nloop = atoi(argv[1]);  
  25.   
  26.         fd = open(IPC_FILE, O_RDWR | O_CREAT, FILE_MODE);  
  27.         if (-1 == fd)  
  28.         {  
  29.                 printf("open %s error!\n", IPC_FILE);  
  30.                 return -1;  
  31.         }  
  32.   
  33.         write(fd, &zero, sizeof(int));  
  34.   
  35.         ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  
  36.   
  37.         close(fd);  
  38.   
  39.         //sem_init(&mutex, 1, 1);//有误,无名信号量需位于共享内存才可在进程间共享  
  40.   
  41.         setbuf(stdout, NULL);  
  42.   
  43.         if (fork() == 0)  
  44.         {  
  45.                 for (i = 0; i < nloop; i++)  
  46.                 {  
  47.                         sem_wait(&mutex);  
  48.                         printf("child: %d\n", (*ptr)++);  
  49.                         sem_post(&mutex);  
  50.                 }  
  51.   
  52.                 return 0;  
  53.         }  
  54.   
  55.         for (i = 0; i < nloop; i++)  
  56.         {  
  57.                 sem_wait(&mutex);  
  58.                 printf("parent: %d\n", (*ptr)++);  
  59.                 sem_post(&mutex);  
  60.         }  
  61.   
  62.         return 0;  
  63. }  
(2)匿名内存映射(用于有亲缘关系的进程间共享。flags:MAP_SHARED | MAP_ANONYMOUS  或 /dev/zero设备,以MAP_ANONYMOUS为例)



  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.   
  9. int main(int argc, char **argv)  
  10. {  
  11.         int i, nloop;  
  12.         int *ptr;  
  13.         sem_t mutex;  
  14.   
  15.         if (argc != 2)  
  16.         {  
  17.                 printf("usage: incr_anonymous \n");  
  18.                 return -1;  
  19.         }  
  20.   
  21.         nloop = atoi(argv[1]);  
  22.   
  23.         ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);/* 匿名映射的内存区被初始化为0 */  
  24.   
  25.         //sem_init(&mutex, 1, 1);//有误,无名信号量需位于共享内存才可在进程间共享  
  26.   
  27.   
  28.         setbuf(stdout, NULL);  
  29.   
  30.         if (fork() == 0)  
  31.         {  
  32.                 for (i = 0; i < nloop; i++)  
  33.                 {  
  34.                         sem_wait(&mutex);  
  35.                         printf("child: %d\n", (*ptr)++);  
  36.                         sem_post(&mutex);  
  37.                 }  
  38.   
  39.                 return 0;  
  40.         }  
  41.   
  42.         for (i = 0; i < nloop; i++)  
  43.         {  
  44.                 sem_wait(&mutex);  
  45.                 printf("parent: %d\n", (*ptr)++);  
  46.                 sem_post(&mutex);  
  47.         }  
  48.   
  49.         return 0;  
  50. }  

二、Posix共享内存区对象

(1)server.c创建共享内存区和有名信号量,并退出,posix共享内存区和有名信号量并不会因为server退出而被删,除非被显式删除。创建共享内存区对象和有名信号量的文件在/dev/shm中。


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.   
  9. #define FILE_MODE       (S_IRWXU | S_IRWXG | S_IRWXO)  
  10. #define SH_NAME         "shm1"  
  11. #define SEM_NAME        "sem1"  
  12. typedef struct  
  13. {  
  14.         int count;  
  15. }SHM_STRUCT;  
  16.   
  17. sem_t *mutex;  
  18.   
  19. int main(int argc, char **argv)  
  20. {  
  21.         int fd;  
  22.         SHM_STRUCT *ptr;  
  23.   
  24.         shm_unlink(SH_NAME);  
  25.         fd = shm_open(SH_NAME, O_RDWR | O_CREAT | O_EXCL, FILE_MODE);  
  26.         if (fd < 0)  
  27.         {  
  28.                 printf("create shared memory error!\n");  
  29.                 return -1;  
  30.         }  
  31.         ftruncate(fd, sizeof(SHM_STRUCT));  
  32.         ptr = mmap(NULL, sizeof(SHM_STRUCT), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  
  33.         close(fd);  
  34.   
  35.         sem_unlink(SEM_NAME);  
  36.         mutex = sem_open(SEM_NAME, O_CREAT | O_EXCL, FILE_MODE, 1);  
  37.         if (mutex == NULL)  
  38.         {  
  39.                 printf("create semaphore error!\n");  
  40.                 return -1;  
  41.         }  
  42.         sem_close(mutex);  
  43.   
  44.         return 0;  
  45. }  


(2)client.c打开共享内存区,并对count进行累加。


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.   
  9. #define FILE_MODE       (S_IRWXU | S_IRWXG | S_IRWXO)  
  10. #define SH_NAME         "shm1"  
  11. #define SEM_NAME        "sem1"  
  12. #define LOOP_NUM        "10000"  
  13.   
  14. typedef struct  
  15. {  
  16.         int count;  
  17. }SHM_STRUCT;  
  18.   
  19. sem_t *mutex;  
  20.   
  21. int main(int argc, char **argv)  
  22. {  
  23.         int fd, i, nloop;  
  24.         pid_t pid;  
  25.         SHM_STRUCT *ptr;  
  26.   
  27.         nloop = atoi(LOOP_NUM);  
  28.   
  29.         fd = shm_open(SH_NAME, O_RDWR, FILE_MODE);  
  30.         if (fd < 0)  
  31.         {  
  32.                 printf("open share memory error!\n");  
  33.                 return -1;  
  34.         }  
  35.         ptr = mmap(NULL, sizeof(SHM_STRUCT), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);  
  36.         close(fd);  
  37.   
  38.         mutex = sem_open(SEM_NAME, 0);  
  39.         if (mutex == NULL)  
  40.         {  
  41.                 printf("open semaphore error!\n");  
  42.                 return -1;  
  43.         }  
  44.   
  45.         pid = getpid();  
  46.         for (i = 0; i < nloop; i++)  
  47.         {  
  48.                 sem_wait(mutex);  
  49.                 printf("pid %ld: %d\n", (long)pid, ptr->count++);  
  50.                 sem_post(mutex);  
  51.         }  
  52.   
  53.         return 0;  
  54. }  



(3)client退出后,共享内存区对象还是存在于系统中的,如果不删除,则之后运行client后,共享内存区里的count变量会不断累加。可以用shm_unlink()和sem_unlink()删除共享内存区对象和有名信号量。


  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8.   
  9. int main(int argc, char **argv)  
  10. {  
  11.         if (argc != 3)  
  12.         {  
  13.                 printf("error command!\n");  
  14.                 return -1;  
  15.         }  
  16.   
  17.         shm_unlink(argv[1]);  
  18.         sem_unlink(argv[2]);  
  19.   
  20.         return 0;  
  21. }  

三、system V共享内存区

虽然现在glibc都支持posix共享内存,但在使用uclibc的嵌入式环境中则是不一定的,还需要用到system v接口。这里先只给出system v共享内存的例子,而system v信号量则留待下一篇写。

首先,封装一下几个接口。

(1)shmOpt.h


  1. #ifndef __SHMOPT_H__  
  2. #define __SHMOPT_H__  
  3.   
  4. #include   
  5.   
  6. #define SHM_KEY 1234  
  7. #define SVSHM_MODE      ((SHM_R) | (SHM_W) | (SHM_R >> 3) | (SHM_R >> 6))  
  8.   
  9. int createShm(key_t key, size_t size);/* 创建共享内存区 */  
  10. void *attachShm(key_t key);/* 连接共享内存区 */  
  11. int dettachShm(const void *shmaddr); /* 断接共享内存区 */  
  12. int destroyShm(key_t key); /* 删除共享内存区 */  
  13. int setShmParam(key_t key, struct shmid_ds *buff); /* 设置共享内存区参数 */  
  14. int getShmParam(key_t key, struct shmid_ds *buff); /* 获取共享内存区参数 */  
  15.   
  16. #endif  

(2)shmOpt.c



  1. #include   
  2. #include "shmOpt.h"  
  3.   
  4. int createShm(key_t key, size_t size)  
  5. {  
  6.         int oflag = SVSHM_MODE | IPC_CREAT;  
  7.         int id = shmget(key, size, oflag);  
  8.   
  9.         if (id < 0)  
  10.         {  
  11.                 printf("%s:create shared memory error!\n", __FUNCTION__);  
  12.         }  
  13.   
  14.         return id;  
  15. }  
  16.   
  17. void *attachShm(key_t key)/* fail:NULL */  
  18. {  
  19.         int oflag = SVSHM_MODE | IPC_CREAT;  
  20.         int id;  
  21.         char *ptr;  
  22.   
  23.         id = shmget(key, 0, oflag);  
  24.         if (id < 0)  
  25.         {  
  26.                 printf("%s:get shared memory error!\n", __FUNCTION__);  
  27.                 return NULL;  
  28.         }  
  29.   
  30.         ptr = shmat(id, NULL, 0);  
  31.         if (*ptr == -1)  
  32.         {  
  33.                 printf("%s:attach shared memory error!\n", __FUNCTION__);  
  34.                 return NULL;  
  35.         }  
  36.   
  37.         return ptr;  
  38. }  
  39.   
  40. int dettachShm(const void *shmaddr)  
  41. {  
  42.         return shmdt(shmaddr);  
  43. }  
  44.   
  45. int destroyShm(key_t key)  
  46. {  
  47.         int id;  
  48.         int oflag = SVSHM_MODE | IPC_CREAT;  
  49.         int ret;  
  50.   
  51.         id = shmget(key, 0, oflag);  
  52.                                                                 if (id < 0)  
  53.         {  
  54.                 printf("%s:get shared memory error!\n", __FUNCTION__);  
  55.                 return -1;  
  56.         }  
  57.   
  58.         ret = shmctl(id, IPC_RMID, NULL);  
  59.         if (ret < 0)  
  60.         {  
  61.                 printf("%s:delete shared memory error!\n", __FUNCTION__);  
  62.                 return -1;  
  63.         }  
  64.   
  65.         return 0;  
  66. }  
  67.   
  68. int setShmParam(key_t key, struct shmid_ds *buff)  
  69. {  
  70.         int id;  
  71.         int oflag = SVSHM_MODE | IPC_CREAT;  
  72.         int ret;  
  73.   
  74.         id = shmget(key, 0, oflag);  
  75.         if (id < 0)  
  76.         {  
  77.                 printf("%s:get shared memory error!\n", __FUNCTION__);  
  78.                 return -1;  
  79.         }  
  80.   
  81.         ret = shmctl(id, IPC_SET, buff);  
  82.         if (ret < 0)  
  83.         {  
  84.                 printf("%s:set parameters error!\n", __FUNCTION__);  
  85.                 return -1;  
  86.         }  
  87.   
  88.         return 0;  
  89. }  
  90.   
  91. int getShmParam(key_t key, struct shmid_ds *buff)  
  92. {  
  93.         int id;  
  94.         int oflag = SVSHM_MODE | IPC_CREAT;  
  95.         int ret;  
  96.   
  97.         id = shmget(key, 0, oflag);  
  98.         if (id < 0)  
  99.         {  
  100.                 printf("%s:get shared memory error!\n", __FUNCTION__);  
  101.                 return -1;  
  102.         }  
  103.   
  104.         ret = shmctl(id, IPC_STAT, buff);  
  105.         if (ret < 0)  
  106.         {  
  107.                 printf("%s:get parameters error!\n", __FUNCTION__);  
  108.                 return -1;  
  109.         }  
  110.   
  111.         return 0;  
  112. }  
  113.             

以下是例子程序。由于没有同步保护,因此首先先用server创建共享内存区,然后再多次调用client看count变量是否能持续累加即可,最后由shmRemove删除共享内存区。


(1)server.c


  1. #include   
  2. #include "shmOpt.h"  
  3.   
  4. typedef struct  
  5. {  
  6.         int count;  
  7. }SHM_STRUCT;  
  8.   
  9. int main()  
  10. {  
  11.         int id;  
  12.   
  13.         id = createShm(SHM_KEY, sizeof(SHM_STRUCT));  
  14.   
  15.         if (id < 0)  
  16.         {  
  17.                 printf("createShm error!\n");  
  18.                 return -1;  
  19.         }  
  20.   
  21.         return 0;  
  22. }  

(2)client.c



  1. #include   
  2. #include "shmOpt.h"  
  3.   
  4. #define LOOP_NUM 1000  
  5.   
  6. typedef struct  
  7. {  
  8.         int count;  
  9. }SHM_STRUCT;  
  10.   
  11. int main()  
  12. {  
  13.         SHM_STRUCT *ptr;  
  14.         struct shmid_ds buff;  
  15.         int i;  
  16.   
  17.         ptr = attachShm(SHM_KEY);  
  18.   
  19.         if (!ptr)  
  20.         {  
  21.                 printf("cannot attach shm!\n");  
  22.                 return -1;  
  23.         }  
  24.   
  25.         for (i = 0; i < LOOP_NUM; i++)  
  26.         {  
  27.                 ptr->count++;  
  28.         }  
  29.   
  30.         printf("ptr->count=%d\n", ptr->count);  
  31.   
  32.         printf("======================\n");  
  33.   
  34.         if (getShmParam(SHM_KEY, &buff) < 0)  
  35.         {  
  36.                 printf("get shmParam error!\n");  
  37.                 return -1;  
  38.         }  
  39.   
  40.         printf("shm size:%d--sizeof(SHM_STRUCT):%d\n", buff.shm_segsz, sizeof(SHM_STRUCT));  
  41.   
  42.         return 0;  
  43. }  

(3)shmRemove.c



  1. #include   
  2. #include "shmOpt.h"  
  3.   
  4. int main()  
  5. {  
  6.         destroyShm(SHM_KEY);  
  7.         return 0;  
  8. }  
阅读(2031) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~