Linux进程间通信--共享内存

一、共享内存定义

百度百科)共享内存指在多处理器的计算机系统中,可以被不同中央处理器访问的大量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进程缓存。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则,不同的处理器可能用到不同的数据。

在Linux系统中,共享内存允许一个进程或多个进程共享一个给定的存储区(共享内存)。不同进程之间共享的内存通常安排为同一段物理地址。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址。这样的一种方式适合于数量级极大和数据结构极为复杂的进程间通信。但这种方式牺牲了系统的安全性,所以通常与其他进程间通信形式混合使用。

注:共享内存并未提供同步机制,也就是说,在第一个结束对共享内存的与操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问。比如:信号量、互斥锁等。

二、使用方法

    1.创建共享内存

      调用接口shmget函数   

            int shmget(key_t key,size_t size ,int shmflg);

       参数

key:标识共享内存的键值:如果是IPC_PRIVATE用于创建当前进程的私有共享内存。

size:共享内存的大小

shmflg:设置共享内存的访问权限

返回值:如果成功返回共享内存标识符,如果失败,返回-1。

            int main()
            {
                int shmid=shmget(IPC_PRIVATE,1024,0666);
                if(shmid<0)
                {
                    printf("error\n");
                }
                else
                {
                    printf("success\n");
                }
                return 0;
            }

在命令行执行ipcs -m显示,已经成功创建了一块内存区

Nattch字段显示已经附加到这个内存区的进程数。  

    2.影射共享内存

            void* shmat(int shmid, char *shmaddr, int flag)

参数:

shmid:shmget函数返回的共享内存标识符

shmaddr:指定共享内存连接到当前进程中的地址位置

它通常是一个空指针

表示让系统来选择共享内存出现的地址

flag:决定以什么样的方式来确定影射的地址(通常为0)

返回值:如果成功,则返回共享内存映射到进程中的地址;

如果失败,则返回-1.

                int main(int args,char *argv[])
                {
                    char *shmbuf=NULL;
                    int shmid=0;
                    if(arg>2)
                    {
                        shmid=atoi(argv[1]);
                        shmbuf=shmat(shmid,0,0);
                        if(atoi(argv[2]==1)
                        {
                            scanf("%s",shmbud);
                        }
                        if(atoi(argv[2])==2)
                        {
                            printf("%s",shmbuf);
                        }
                        shmdt(shmbuf);//将共享内存从进程中分离出去
                    }
                    return 0;
                }

注意:通过  ipcs -m命令看到nattch字段显示有一个进程附加到共享内存。

3.解除共享内存映射

函数shmdt是将附加在shmaddr的段从调用进程的地址空间分离出去,这个地址必须是shmat返回的地址。

            int shmdt(char *shmaddr);

函数调用成功返回0,失败返回-1。

4.控制共享内存

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

     参数:

shmid是shmget函数返回的共享内存标识符。

command:要采取的操作,它可以取下面的三个值

IPC_STAT:是把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。

IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值

IPC_RMID:删除共享内存段

buf:buf是一个结构指针,它指向共享内存模式和访问权限的结构。

shmid_ds结构:

            struct shmid_ds
            {
                uid_t shm_perm.uid;
                uid_t shm_perm.gid;
                mode_t shm_perm.mode;
            };

5.代码实例

            往共享内存写:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<errno.h>
#define VALUE_SIZE 2048
struct share_use_st
{
    int write_flag;//作为一个标志,非0表示可读,0表示可写
    char value[VALUE_SIZE];//记录写入和读取的文本
};
int main()
{
   int run=1;
   void *shm=NULL;
   struct share_use_st *share=NULL;
   char buf[VALUE_SIZE+1];
   int shmid;
   shmid=shmget((key_t)123,sizeof(struct share_use_st),0666|IPC_CREAT);
   if(shmid==-1)
   {
       printf("%s\n",strerror(errno));
       exit(EXIT_FAILURE);
   }
   shm=shmat(shmid,NULL,0);
   if(shm==(void *)-1)
   {
       printf("%s\n",strerror(errno));
       exit(EXIT_FAILURE);
   }
   printf("\nMemory attached at %p\n",shm);
   //设置共享内存
   share=(struct share_use_st*)shm;

   while(run)
   {
      while(share->write_flag==1)
      {
          sleep(1);
          printf("waiting....\n");
      }
      printf("Enter some value:");
      read(STDIN_FILENO,buf,sizeof(buf)-1);
      strncpy(share->value,buf,VALUE_SIZE);
      share->write_flag=1;
      if(strncmp(buf,"end",3)==0)
      {
          run=0;
      }
   }
   if(shmdt(shm)==-1)
   {
       printf("%s\n",strerror(errno));
       exit(EXIT_FAILURE);
   }
   sleep(2);
   return 0;
}

        从共享内存读:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/shm.h>
#include<errno.h>
#define VALUE_SIZE 2048
struct share_use_st
{
    int write_flag;//作为一个标志,非0表示可读,0表示可写
    char value[VALUE_SIZE];//记录写入和读取的文本
};
int main(int args,char *argv[])
{
    int run=1;
    void *shmbuf=NULL;//共享内存的地址
    struct share_use_st *shm;
    int shmid;//共享内存标识符
    shmid=shmget((key_t)123,sizeof(struct share_use_st),0666|IPC_CREAT);
    if(shmid==-1)
    {
        printf("%s\n",strerror(errno));
        exit(EXIT_FAILURE);
    }
    //将共享内存连接到当前进程的地址空间
    shmbuf=shmat(shmid,0,0);
    if(shmbuf==(void *)-1)
    {
        printf("%s",strerror(errno));
        exit(EXIT_FAILURE);
    }
    printf("\nMemory attach at %x",(int)shm);
    //设置共享内存
    shm=(struct share_use_st*)shmbuf;
    shm->write_flag=0;
    while(run)
    {
        if(shm->write_flag!=0)
        {
            printf("recv:%s\n",shm->value);
            sleep(rand()%3);
            //读取完数据,设置write_flag使共享内存可写
            shm->write_flag=0;
            //输入了end,退出循环
            if(strncmp(shm->value,"end",3)==0)
                run=0;
        }
        else
        {
            sleep(1);
        }
    }
    //把共享内存从当前进程中分离
    if(shmdt(shmbuf)==-1)
    {
        printf("%s",strerror(errno));
        exit(EXIT_FAILURE);
    }
    //删除共享内存
    if(shmctl(shmid,IPC_RMID,0)==-1)
    {
        printf("%s\n",strerror(errno));
        exit(EXIT_FAILURE);
    }
    return EXIT_SUCCESS;
}

三、使用共享内存的优缺点

优点:使用共享内存进行进程间通信非常方便,函数接口也简单,数据的共享还使进程通信时直接访问内存,省去了传送的时间,加快了效率;同时也不想无名管道那样要求通信的进程有一定的父子关系。

缺点:共享内存没有提供同步的机制,这使得我们在使用共享内存时,往往要借助其他的方式来进行进程间的同步问题。

时间: 2024-10-10 16:49:13

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

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

下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程. 特别提醒:共

Linux进程间通信—共享内存

五.共享内存(shared memory) 共享内存映射为一段可以被其他进程访问的内存.该共享内存由一个进程所创建,然后其他进程可以挂载到该共享内存中.共享内存是最快的IPC机制,但由于linux本身不能实现对其同步控制,需要用户程序进行并发访问控制,因此它一般结合了其他通信机制实现了进程间的通信,例如信号量. 共享内存与多线程共享global data和heap类似.一个进程可以将自己内存空间中的一部分拿出来,允许其它进程读写.当使用共享内存的时候,我们要注意同步的问题.我们可以使用 sema

Linux进程间通信 -- 共享内存 shmget()、shmat()、shmdt()、shmctl()

下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc()分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程. 特别提醒

Linux 进程间通信 - 共享内存shmget方式

共享内存区域是被多个进程共享的一部分物理内存.如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容.这块共享虚拟内存的页面,出现在每一个共享该页面的进程的页表中.但是它不需要在所有进程的虚拟内存中都有相同的虚拟地址 以下是使用共享内存机制进行进程间通信的基本操作: 需要包含的头文件: #include

Linux进程间通信 共享内存+信号量+简单例子

每一个进程都有着自己独立的地址空间,比如程序之前申请了一块内存,当调用fork函数之后,父进程和子进程所使用的是不同的内存.因此进程间的通信,不像线程间通信那么简单.但是共享内存编程接口可以让一个进程使用一个公共的内存区段,这样我们便能轻易的实现进程间的通信了(当然对于此内存区段的访问还是要控制好的). 共享内存实现进程通信的优点: 共享内存是进程通信方式中最快速的方式之一,它的快速体现在,为数据共享而进行的复制非常少.这里举例来说,使用消息队列时,一个进程向消息队列写入消息时,这里有一次数据的

Linux进程间通信 共享内存+信号量+简单样例

每个进程都有着自己独立的地址空间,比方程序之前申请了一块内存.当调用fork函数之后.父进程和子进程所使用的是不同的内存. 因此进程间的通信,不像线程间通信那么简单.可是共享内存编程接口能够让一个进程使用一个公共的内存区段,这样我们便能轻易的实现进程间的通信了(当然对于此内存区段的訪问还是要控制好的). 共享内存实现进程通信的长处: 共享内存是进程通信方式中最高速的方式之中的一个,它的高速体如今,为数据共享而进行的复制很少.这里举例来说.使用消息队列时.一个进程向消息队列写入消息时.这里有一次数

Linux --进程间通信--共享内存

一.共享内存 共享内存是最高效的通信方式,因为不需要一个进程先拷贝到内核,另一个进程在存内核中读取. 二. ipcs -m 查看共享内存 ipcrm -m 删除共享内存 三.主要函数 shmget 创建 shmctl 删除 shmat 挂接 shmdt 取消挂接 ********* man 函数名 查看***** 四.代码实现 comm.h   1 #pragma once   2 #include<stdio.h>   3 #include<stdlib.h>   4 #incl

C# 进程间通信(共享内存)

原文:C# 进程间通信(共享内存) 进程间通信的方式有很多,常用的方式有: 1.共享内存(内存映射文件,共享内存DLL). 2.命名管道和匿名管道. 3.发送消息 本文是记录共享内存的方式进行进程间通信,首先要建立一个进程间共享的内存地址,创建好共享内存地址后,一个进程向地址中写入数据,另外的进程从地址中读取数据. 在数据的读写的过程中要进行进程间的同步. 进程间数据同步可以有以下的方式 1. 互斥量Mutex 2. 信号量Semaphore 3. 事件Event 本文中进程间的同步采用 信号量

Linux IPC 共享内存用法

Linux IPC 常见的方式 写 Linux Server 端程序,必然会涉及到进程间通信 IPC. 通信必然伴随着同步机制,下面是一些常见的通信与同步机制: 进程间通信:匿名管道,命名管道,消息队列,共享内存,Domain Socket, 本机 TCP Socket,文件 进程间同步:信号,信号量 线程间同步:条件变量,互斥量,读写锁,自旋锁,Barrier. 对于大部分的业务场景,本机 TCP Socket 足以,现在Linux 也对本机 TCP Socket做了很好的优化.而且如果以后需