Linux进程间通信共享内存

http://blog.csdn.net/shui1025701856/article/details/7484203 

进程可以直接读写内存,不需要任何数据的复制。为了在多个进程间交换
信息,内核专门留出一块内存区,内存区可以由需要访问的进程将其映射
到自己的私有地址空间,进程直接读写这一内存区,而不需要进行数据
的复制,提高了效率。由于多个进程共享内存,需要依靠同步机制如
互斥锁和信号量。

共享内存的实现分为三个步骤:

1. 创建共享内存,shmget()
shmget(创建或打开共享内存)
表头文件 #include <sys/ipc.h>
#include <sys/shm.h>
函数定义   int shmget(key_t key, size_t size, int shmflg);
函数说明 key:IPC_PRIVATE或ftok的返回值,标识的ID
       size:共享内存区大小。shmflg:同 open函数的权限位,也可以用8进制表示法
返回值:成功返回内存标识符,错误返回-1
#define IPC_CREAT01000 /* Create key if key does not exist. */
#define IPC_EXCL02000 /* Fail if key exists.  */
#define IPC_NOWAIT04000 /* Return error on wait.  */
2. 映射共享内存,把创建的共享内存映射到具体的进程空间,shmat()
shmat(映射共享内存)
表头文件 #include <sys/types.h>
      #include <sys/shm.h>
函数定义 void *shmat(int shmid, const void *shmaddr, int shmflg);


函数说明 shmid:要映射的共享内存区标识符
shmaddr:将共享内存映射到指定地址(若为NULL,则表示由系统自动完成映射)
shmflg:SHM_RDONLY:共享内存只读,默认为0,共享内存可读写
返回值:成功映射后的地址,错误:-1
3. 撤销映射shmdt()
shmdt(共享内存从进程中分离出来)
表头文件:  #include <sys/types.h>
         #include <sys/shm.h>
函数定义:  int shmdt(const void *shmaddr);
函数说明:shmaddr:共享内存后映射的地址
返回值:成功0,错误-1
案例:创建一个共享内存区,之后创建子进程,在父子两个进程中将共享内存
分别映射到各自的地址空间中
父进程先等待用户输入,然后用户输入的字符串写入到共享内存,之后往共享
内存的头部写入WROTE字符串表示进程已成功写入数据。子进程一直等到共享
内存的头部字符串为WROTE,然后将共享内存的有效数据(在父进程中用户输入的字符串)
在屏幕上打印。父子两个进程在工作之后,分别解除与共享内存的映射关系。
用标志字符串来实现父子之间的同步
命令ipcs,用于报告进程间通信机制状态的命令,它可以查看共享内存,消息队列
等各种进程间通信机制的情况,用system()函数调用shell命令ipcs

 

[csharp] view plaincopy
 
    1. sem_com.h  
    2. -------------------------------------  
    3. #ifndef __SEM_COM_H__  
    4. #define __SEM_COM_H__  
    5. /** 
    6. *信号量相关的函数调用接口复杂,将它们封装成二维单个 
    7. *信号量的几个基本函数。 
    8. *信号量初始化函数init_sem() 
    9. *P操作加一sem_p() 
    10. *V操作减一sem_v() 
    11. *从系统中删除信号量del_sem() 
    12. */  
    13. #include <sys/types.h>  
    14. #include <sys/ipc.h>  
    15. #include <sys/sem.h>  
    16.   
    17. union semun {  
    18.     int val;  
    19. };  
    20. extern int init_sem(int sem_id, int init_value);  
    21. extern int sem_p(int sem_id);  
    22. extern int sem_v(int sem_id);  
    23. extern int del_sem(int sem_id);  
    24. #endif  
    25. ----------------------------------------------------  
    26. sem_com.c  
    27. -----------------------------------------------------  
    28. #include "sem_com.h"  
    29.   
    30. /**信号量初始化函数*/  
    31. int init_sem(int sem_id, int init_value)  
    32. {  
    33.     union semun sem_union;  
    34.     sem_union.val = init_value; //init_value为初始值  
    35.     if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {  
    36.         perror("Initialize semaphore");  
    37.         return -1;  
    38.     }  
    39.     return 0;  
    40. }  
    41.   
    42. /**从系统中删除信号量的函数*/  
    43. int del_sem(int sem_id)  
    44. {  
    45.     union semun sem_union;  
    46.     if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1) {  
    47.         perror("Delete semaphore");  
    48.         return -1;  
    49.     }  
    50. }  
    51.   
    52. /**P操作*/  
    53. int sem_p(int sem_id)  
    54. {  
    55.     struct sembuf sem_b;  
    56.     sem_b.sem_num = 0;//单个信号量的编号应该为0  
    57.     sem_b.sem_op = -1;//表示P操作  
    58.     sem_b.sem_flg = SEM_UNDO;//系统自动释放将会在系统中残留的信号量  
    59.     if (semop(sem_id, &sem_b, 1) == -1) {  
    60.         perror("semop");  
    61.         return -1;  
    62.     }  
    63.     return 0;  
    64. }  
    65.   
    66. /**V操作*/  
    67. int sem_v(int sem_id)  
    68. {  
    69.     struct sembuf sem_b;  
    70.     sem_b.sem_num = 0;//单个信号量的编号应该为0  
    71.     sem_b.sem_op = 1;//表示V操作  
    72.     sem_b.sem_flg = SEM_UNDO;  
    73.     if (semop(sem_id, &sem_b, 1) == -1) {  
    74.         perror("semop V");  
    75.         return -1;  
    76.     }  
    77.     return 0;  
    78. }  
    79. ----------------------------------------------------  
    80. shmem.c  
    81. ----------------------------------------------------  
    82. #include <sys/types.h>  
    83. #include <sys/ipc.h>  
    84. #include <sys/shm.h>  
    85. #include <sys/sem.h>  
    86. #include <stdio.h>  
    87. #include <stdlib.h>  
    88. #include <string.h>  
    89. #include <unistd.h>  
    90. #include "sem_com.h"  
    91.  
    92. #define BUFFER_SIZE 2048  
    93.   
    94. pid_t pid;  
    95. int shmid;//要映射的共享内存区标识符  
    96. int semid;//定义信号量,用于实现共享内存的进程之间的互斥  
    97. char *shm_addr;//共享内存映射到的地址  
    98. char buff[BUFFER_SIZE];  
    99.       
    100. void function_init()  
    101. {  
    102.       
    103.     //创建一个信号量  
    104.     semid = semget(ftok("/home",2), 1, 0666|IPC_CREAT);  
    105.     init_sem(semid, 1);//初始值为1  
    106.       
    107.     //创建共享内存  
    108.     shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666);  
    109.     if (shmid < 0) {  
    110.         perror("shmget");  
    111.         exit(1);  
    112.     } else {  
    113.         printf("create shard-memory shmid: %d\n", shmid);  
    114.     }  
    115.       
    116. }  
    117.   
    118. void function_end()  
    119. {  
    120.       
    121.     //删除信号量  
    122.     del_sem(semid);   
    123.     //解除共享内存映射  
    124.     if ((shmdt(shm_addr)) < 0) {  
    125.         perror("shmdt");  
    126.         exit(1);  
    127.     }   
    128.           
    129.     //删除共享内存IPC_RMID    删除共享内存段  
    130.     if (shmctl(shmid, IPC_RMID, NULL) == -1) {  
    131.         perror("shmctl");  
    132.         exit(1);  
    133.     } else {  
    134.         printf("Delete shared-memory\n");  
    135.     }  
    136.           
    137. }  
    138. int main()  
    139. {  
    140.       
    141.     function_init();  
    142.       
    143.     pid = fork();  
    144.     if (pid == 0) {//子进程  
    145.         //映射共享内存  
    146.         shm_addr = shmat(shmid, NULL, 0);  
    147.         if (shm_addr == (void *)-1) {  
    148.             perror("Child: shmat");  
    149.             exit(1);  
    150.         } else  
    151.         {  
    152.             do{  
    153.                 sem_p(semid);  
    154.                 printf("\nChild:Attach shared-memory %p :%s \n", shm_addr, shm_addr);  
    155.                 if (strncmp(shm_addr, "quit", 4) == 0) {  
    156.                     break;  
    157.                 }  
    158.                 memset(shm_addr, 0, BUFFER_SIZE);  
    159.                 sem_v(semid);  
    160.             } while(1);  
    161.               
    162.         }  
    163.         //显示共享内存情况  
    164.         //system("ipcs -m");  
    165.           
    166.     } else if(pid > 0){//父进程  
    167.         //映射共享内存  
    168.         shm_addr = shmat(shmid, 0, 0);  
    169.           
    170.         //父进程向共享内存定入数据  
    171.         do {  
    172.               
    173.             sem_p(semid);//信号值减一  
    174.             printf("Parent:Enter some text to the shared memory(enter 'quit' to exit):\n");  
    175.             if(fgets(buff, BUFFER_SIZE, stdin) == NULL) {  
    176.                 perror("fgets");  
    177.                 sem_v(semid);  
    178.                 break;  
    179.             }  
    180.             strncpy(shm_addr, buff, strlen(buff));  
    181.             sem_v(semid);  
    182.         } while(strncmp(buff, "quit", 4) != 0);  
    183.                   
    184.         function_end();   
    185.     }  
    186.       
    187.       
    188.           
    189.     exit(0);  
    190. }  
    191. ---------------------------------------------------  
    192.  shmem#./bts   
    193. create shard-memory shmid: 1966089  
    194. PARENTS:Enter some text to the shared memory(enter 'quit' to exit):  
    195. hi child! "good afternoon"  
    196.   
    197. Child:Attach shared-memory 0xb78af000 :hi child! "good afternoon"  
    198.    
    199. PARENTS:Enter some text to the shared memory(enter 'quit' to exit):  
    200. ok let's go  
    201.   
    202. Child:Attach shared-memory 0xb78af000 :ok let's go  
    203.    
    204. PARENTS:Enter some text to the shared memory(enter 'quit' to exit):  
    205. quit  
    206. Delete shared-memory  
    207.   
    208. Child:Attach shared-memory 0xb78af000 :quit  
    209.    
posted @ 2015-08-12 11:57  jimshi  阅读(548)  评论(0编辑  收藏  举报