Linux进程间通信——使用共享内存

原文链接: https://blog.csdn.net/ljianhui/article/details/10253345
  • 共享内存允许多个进程共享一个给定的内存空间,进程可以直接读写内存,因此是IPC中速度最快的。

  • Linux中,内核专门留出了一块内存区作为共享内存区,用于多个进程交换信息。需要通信的进程将共享内存区映射到自己的私有地址空间,从而使读写进程地址空间就相当于读写内存区。使用共享内存的头文件是#include

  • 由于多个进程读写同一块内存区,所以需要进行同步处理,一般要和信号量联合使用(也可使用互斥量和记录锁)。

    • Linux进程间通信——使用共享内存_第1张图片
  • 共享内存段默认是32M字节。
  • 共享内存的操作流程(只使用于相关进程,即亲缘进程间的通信):

    • 创建/打开一块共享内存区
    • 把指定的共享内存映射到进程的地址空间
    • 撤销共享内存映射
    • 删除共享内存对象(key代表的IPC对象)
  • 共享内存常用函数:

    • shmget(key, size, flag):创建新的共享内存段或者取得已有的共享内存段,函数返回共享存储段的ID(shmid)。key标识共享内存的键值,两个进程用相同的key时用shmget得到的shmid是相同的,此时可以访问同一块共享内存。size表示获得的共享内存大小。flag表示共享内存块的访问权限,如果想共享内存段不存在时新建一个,用IPC_CREAT与权限值做位与操作即可。

    • shmat(shmid, addr, flag):将共享存储段映射到进程的地址空间。应当制定addr为0,由系统选择地址(该地址位于堆栈之间)。 flag是一组标志位,一般也为0。调用成功后,返回指向共享内存第一个字节的指针。

    • shmdt(addr):将进程地址空间与该共享内存段分离,使该共享内存对当前进程而言不可用。

    • shmctl(shm_id, command, buf):控制共享内存。command参数:IPC_RMID(删除共享内存段)、IPC_STAT和IPC_SET(不常用)

  • 无关进程(非亲缘进程)共享内存的方法:

    • 使用XSI共享存储函数
    • 使用mmap将同一文件映射到多个进程的地址空间,为此要使用MAP_SHARED标志以保证:一个进程写到存储段,另一个进程可见。
  • 使用共享内存的优缺点:
    • 优点:方便,接口简单;数据不用传送而是直接读写内存,效率高;没有无名管道那种亲缘进程才能通信的限制,适用于不相关进程通信。
    • 缺点:需要借助外部的同步机制
  • 共享内存的使用例子,创建两个进程,shmwrite向共享内存写数据,shmread从共享内存读数据:
    • shmread进程,创建一块共享内存段,将共享内存段映射到自己的内存空间,从内存中读数据。
      #include   
      #include   
      #include   
      #include 
      struct shared_use_st  
      {  
          int wirte_read_flag;        //作为一个标志,非0:表示可读,0表示可写  
          char text[1024];              //记录写入和读取的文本  
      };
      int main()  
      {  
          int running = 1;    //程序是否继续运行的标志  
          void *shm = NULL;    //分配的共享内存的原始首地址  
          struct shared_use_st *shared;   //指向shm  
          int shmid;         //共享内存标识ID号  
          //创建共享内存,当key一样时返回的shmid也是一样的,则两个进程使用同一块共享内存,IPC_CREAT表示创建一块指定key的共享内存块
          shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);  
          if(shmid == -1)  
          {  
              fprintf(stderr, "shmget failed\n");  
              exit(EXIT_FAILURE);  
          }  
          //将共享内存连接到当前进程的地址空间  
          shm = shmat(shmid, 0, 0);  
          if(shm == (void*)-1)  
          {  
              fprintf(stderr, "shmat failed\n");  
              exit(EXIT_FAILURE);  
          }  
          printf("\nMemory attached at %X\n", (int)shm);  
          //设置共享内存  
          shared = (struct shared_use_st*)shm;  
          shared->wirte_read_flag = 0;  //设为可写
          while(running)   //读取共享内存中的数据  
          {  
              //可读模式,从进程的地址空间shm里读就相当于从共享内存里读
              if(shared->wirte_read_flag != 0)  
              {  
                  printf("Receive Message: %s", shared->text);  
                  sleep(rand() % 3);  
                  //读取完数据,设置wirte_read_flag使共享内存段可写  
                  shared->wirte_read_flag = 0;  
                  //输入了end,退出循环  
                  if(strncmp(shared->text, "end", 3) == 0)  
                      running = 0;  
              }  
              else        //有其他进程在写数据,不能读取数据  
                  sleep(1);  
          }  
          //把共享内存从当前进程中分离  
          if(shmdt(shm) == -1)  
          {  
              fprintf(stderr, "shmdt failed\n");  
              exit(EXIT_FAILURE);  
          }  
          //删除共享内存  
          if(shmctl(shmid, IPC_RMID, 0) == -1)  
          {  
              fprintf(stderr, "shmctl(IPC_RMID) failed\n");  
              exit(EXIT_FAILURE);  
          }  
          exit(EXIT_SUCCESS);  
      }
      #include   
      #include   
      #include   
      #include   
      #include   
      struct shared_use_st  
      {  
          int wirte_read_flag;        //作为一个标志,非0:表示可读,0表示可写  
          char text[1024];              //记录写入和读取的文本  
      };
      int main()  
      {  
          int running = 1;  
          void *shm = NULL;  
          struct shared_use_st *shared = NULL;  
          char buffer[1024 + 1];  //用于保存输入的文本  
          int shmid;  
          //创建共享内存,当key一样时,返回的shmid也是一样的,则两个进程访问同一块共享内存,IPC_CREAT表示创建一块指定key的共享内存
          shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);  
          if(shmid == -1)  
          {  
              fprintf(stderr, "shmget failed\n");  
              exit(EXIT_FAILURE);  
          }  
          //将共享内存连接到当前进程的地址空间  
          shm = shmat(shmid, (void*)0, 0);  
          if(shm == (void*)-1)  
          {  
              fprintf(stderr, "shmat failed\n");  
              exit(EXIT_FAILURE);  
          }  
          printf("Memory attached at %X\n", (int)shm);  
          //设置共享内存  
          shared = (struct shared_use_st*)shm;  
          while(running)    //向共享内存中写数据  
          {  
              //数据还没有被读取,则等待数据被读取,不能向共享内存写
              while(shared->wirte_read_flag == 1)  
              {  
                  sleep(1);  
                  printf("Waiting...\n");  
              }  
              //向共享内存中写入数据,向进程的地址空间shm里写就相当于往共享内存里写!  
              printf("Enter some text: ");  
              fgets(buffer, BUFSIZ, stdin);  
              strncpy(shared->text, buffer, 1024);  
              //写完数据,设置written使共享内存段可读  
              shared->wirte_read_flag = 1;  
              //输入了end,退出循环  
              if(strncmp(buffer, "end", 3) == 0)  
                  running = 0;  
          }  
          //把共享内存从当前进程中分离  
          if(shmdt(shm) == -1)  
          {  
              fprintf(stderr, "shmdt failed\n");  
              exit(EXIT_FAILURE);  
          }  
          sleep(2);  
          exit(EXIT_SUCCESS);  
      }

       

你可能感兴趣的:(Linux进程间通信——使用共享内存)