进程间通信IPC之--共享内存

每个进程各自有不同的用户地址空间,任何一个进 程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲 区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)

如下图所示:

进程间通信共七种方式:

第一类:传统的unix通信机制:

# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
# 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

# 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

第二类:System V IPC: 
# 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

第三类:BSD 套接字:

# 套接字( socket ) : 套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

本文介绍IPC之共享内存:

共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。进程可以直接读取共享内存,不需要拷贝数据。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。

步骤:

共享内存的使用,主要有以下几个API:ftok()、shmget()、shmat()、shmdt()及shmctl()

①创建/打开共享内存

int shmget(key_t key,int size,int shmflag);

例:

key = ftok(".", ‘m‘);

shmid = shmget(key,1024,0666|IPC_CREAT|IPC_EXCL);

参数说明:

key:是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。如果两个进程没有任何关系,所以就用ftok()算出来一个标识符(或者自己定义一个)使用了。

产生key的方法:key_t ftok(const char *pathname, int proj_id);

1)pathname一定要在系统中存在并且进程能够访问的

2)proj_id是一个1-255之间的一个整数值,典型的值是一个ASCII值。如‘a‘,考虑到应用系统可能在不同的主机上应用,可以直接定义一个key,而不用ftok获得:

#define IPCKEY 0x344378

size:申请内存的大小

shmflag:  这块内存的模式(mode)以及权限标识(0666等)。

模式可取如下值:        
IPC_CREAT 新建(如果已创建则返回目前共享内存的id)
IPC_EXCL   与IPC_CREAT结合使用,如果已创建则则返回错误

其他模式略

申请的内存里面为空,即全为0

②映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问

void *shmat( int shmid , char *shmaddr , int shmflag );

例:

void *p;

p=shmat(shmid,NULL,0);

参数说明:

shmid:是那块共享内存的ID。

shmaddr:共享内存映射的起始地址,一般不指定即NULL

shmflag:本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。0是读写模式

返回值: 成功时,这个函数返回共享内存的起始地址。失败时返回-1。

③撤销共享内存映射,删除本进程对这块内存的使用

int shmdt(const void* shmaddr);

例:

shmdt(p);

参数说明:

shmaddr:共享内存的起始地址。

返回值:成功时返回0。失败时返回-1。

④删除共享内存对象

int shmctl( int shmid , int cmd , struct shmid_ds *buf );

例:

shmctl(shmid, IPC_RMID, NULL);(删除共享内存)
参数说明:

shmid:共享内存的ID。
cmd:控制命令,可取值如下:
        IPC_STAT        得到共享内存的状态
        IPC_SET         改变共享内存的状态
        IPC_RMID        删除共享内存
buf:一个结构体指针。用以保存/设置属性。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。
返回值:成功时返回0。失败时返回-1。

无代码无真相

功能说明:两个进程通过共享内存一个写一个读并打印数据

  1. /*name:writer.c
  2. *function:写端进程向共享内存写数据
  3. * */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <errno.h>
  8. #include <signal.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <sys/ipc.h>
  12. #include <sys/shm.h>
  13. #define N 64
  14. typedef struct
  15. {
  16. pid_t pid;
  17. char buf[N];
  18. } SHM;
  19. void handler(int signo)
  20. {
  21. //printf("get signal\n");
  22. return;
  23. }
  24. int main()
  25. {
  26. key_t key;
  27. int shmid;
  28. SHM *p;
  29. pid_t pid;
  30. if ((key = ftok(".", ‘m‘)) < 0)
  31. {
  32. perror("fail to ftok");
  33. exit(-1);
  34. }
  35. signal(SIGUSR1, handler);//注册一个信号处理函数
  36. if ((shmid = shmget(key, sizeof(SHM), 0666|IPC_CREAT|IPC_EXCL)) < 0)
  37. {
  38. if (EEXIST == errno)//存在则直接打开
  39. {
  40. shmid = shmget(key, sizeof(SHM), 0666);
  41. p = (SHM *)shmat(shmid, NULL, 0);
  42. pid = p->pid;
  43. p->pid = getpid();
  44. kill(pid, SIGUSR1);
  45. }
  46. else//出错
  47. {
  48. perror("fail to shmget");
  49. exit(-1);
  50. }
  51. }
  52. else//成功
  53. {
  54. p = (SHM *)shmat(shmid, NULL, 0);
  55. p->pid = getpid();//把自己的pid写到共享内存
  56. pause();
  57. pid = p->pid;//得到读端进程的pid
  58. }
  59. while ( 1 )
  60. {
  61. printf("write to shm : ");
  62. fgets(p->buf, N, stdin);//接收输入
  63. kill(pid, SIGUSR1);//向读进程发SIGUSR1信号
  64. if (strcmp(p->buf, "quit\n") == 0) break;
  65. pause();//阻塞,等待信号
  66. }
  67. shmdt(p);
  68. shmctl(shmid, IPC_RMID, NULL);//删除共享内存
  69. return 0;
  70. }
  1. /*name:reader.c
  2. *function:读端进程从共享内存中读数据
  3. * */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <errno.h>
  8. #include <signal.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <sys/ipc.h>
  12. #include <sys/shm.h>
  13. #define N 64
  14. typedef struct
  15. {
  16. pid_t pid;
  17. char buf[N];
  18. } SHM;
  19. void handler(int signo)
  20. {
  21. //printf("get signal\n");
  22. return;
  23. }
  24. int main()
  25. {
  26. key_t key;
  27. int shmid;
  28. SHM *p;
  29. pid_t pid;
  30. if ((key = ftok(".", ‘m‘)) < 0)
  31. {
  32. perror("fail to ftok");
  33. exit(-1);
  34. }
  35. signal(SIGUSR1, handler);//注册一个信号处理函数
  36. if ((shmid = shmget(key, sizeof(SHM), 0666|IPC_CREAT|IPC_EXCL)) < 0)
  37. {
  38. if (EEXIST == errno)//存在则直接打开
  39. {
  40. shmid = shmget(key, sizeof(SHM), 0666);
  41. p = (SHM *)shmat(shmid, NULL, 0);
  42. pid = p->pid;
  43. p->pid = getpid();//把自己的pid写到共享内存
  44. kill(pid, SIGUSR1);
  45. }
  46. else//出错
  47. {
  48. perror("fail to shmget");
  49. exit(-1);
  50. }
  51. }
  52. else//成功
  53. {
  54. p = (SHM *)shmat(shmid, NULL, 0);
  55. p->pid = getpid();
  56. pause();
  57. pid = p->pid;//得到写端进程的pid
  58. }
  59. while ( 1 )
  60. {
  61. pause();//阻塞,等待信号
  62. if (strcmp(p->buf, "quit\n") == 0) exit(0);//输入"quit结束"
  63. printf("read from shm : %s", p->buf);
  64. kill(pid, SIGUSR1);//向写进程发SIGUSR1信号
  65. }
  66. return 0;
  67. }

时间: 2024-07-29 18:23:23

进程间通信IPC之--共享内存的相关文章

进程间通信(IPC)之共享内存

★IPC方法包括管道(PIPE).消息队列(Message_Queue).旗语.共用内存(ShareMemory)以及套接字 (Socket).进程间通信主要包括了管道.系统IPC(包括了消息队列.信号以及共享存储).套接字(Socket). 此文将叙述共享内存的相关内容. 在此之前先来看看关于进程的内存映像的相关内容. 一.进程的内存映像(区别于可执行程序文件): 指的是内核在内存中如何存放可执行程序文件.两者的区别表现在三个方面:①可执行程序是位于硬盘上的,而内存映像位 于内存上: ②可执行

Linux IPC之共享内存C 事例

Linux IPC之共享内存 标签: linuxrandomnull工作 2011-08-25 11:52 4123人阅读 评论(0) 收藏 举报  分类: Linux(3)  读书札记(3)  版权声明:本文为博主原创文章,未经博主允许不得转载. 简介 共享内存(shared memory)是最简单的Linux进程间通信方式之一.使用共享内存,不同进程可以对同一块内存进行读写.由于所有进程对共享内存的访问就和访问自己的内存空间一样,而不需要进行额外系统调用或内核操作,同时还避免了多余的内存拷贝

linux ftok()函数 --多进程IPC之共享内存

系统建立IPC通讯(如消息队列.共享内存时)必须指定一个ID值.通常情况下,该id值通过ftok函数得到.ftok原型如下:key_t ftok( char * fname, int id ) fname就时你指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255). 当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回. 在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值.如指定文件的索引节

System V IPC 之共享内存

IPC 是进程间通信(Interprocess Communication)的缩写,通常指允许用户态进程执行系列操作的一组机制: 通过信号量与其他进程进行同步 向其他进程发送消息或者从其他进程接收消息 和其他进程共享一段内存区 System V IPC 最初是在一个名为 "Columbus Unix" 的开发版 Unix 变种中引入的,之后在 AT&T 的 System III 中采用.现在在大部分 Unix 系统 (包括 Linux) 中都可以找到. IPC 资源包含信号量.

linux进程间通信,使用共享内存方式

闲来没事给想要学习进程间使用共享内存通信的例子,共享内存的效率比消息队列.信号量都要高?为什么呢? (1)共享内存是运行在用户空间的,由应用程序控制. (2)消息队列和信号量都是把数据从一个进程用户空间复制到内核空间,然后再由内核控件复制到另外一个进程的用户空间. #include <unistd.h> #include <stdio.h> #include <string.h> #include <sys/mman.h> #include <sys/

IPC: 共享内存

################################################### 共享内存区   共享内存是IPC形式中最快的,因为共享内存不和内核进行数据交换. 通过fork派生的子进程不与父进程共享内存区.   共享内存区分为: 1.posix共享内存区 2.system V共享内存区 共享内存有两种形式: 1.匿名共享内存 2.有名共享内存 ----------------------------------------------------------- posi

进程间通信三(共享内存)

1.什么是共享内存? 共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程.共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之

Unix IPC之共享内存区(1)

1 共享内存区 共享内存区是可用IPC形式中最快的,只有映射和解除映射需要进入内核的系统调用,映射后对共享内存区的访问和修改不再需要系统调用(内核只要负责好页表映射和处理页面故障即可),但通常需要同步手段. 一个客户-服务器间传递文件数据的例子中,FIFO或消息队列等IPC方式通常需要4次内核-进程间的数据复制(但是Posix消息队列可使用内存映射I/O实现,就不一定4次了),每次都需要切换地址空间,开销很大:共享内存区只需要2次跨内核的数据复制. 2  mmap mmap的三个目的: 1.  

Linux IPC之共享内存

System V共享内存机制: shmget  shmat  shmdt  shmctl 原理及实现: system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去.这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信. 共享内存允许一个或多个进程通过