ROS系统节点间的内存共享

痞子三分冷 提交于 2020-01-31 01:08:38

为什么要用内存共享?

答案是ROS提供的服务或者话题都是通过网络来实现的。照顾到ROS节点可能架设在不同的硬件上这一点,这样做更具普遍性,但对于在同一台设备的两个节点间传输数据是非常不友好的。因为其既没必要性又浪费大量资源,且效率低下,容易造成网络堵塞,延时严重。

那么怎么改善最好呢,自然是进程间的内存共享。我们直接让两个节点共享一片物理内存,在里面做一个队列数据结构,一个往里面写,一个去里面读。

下面我们就来实现这一功能。跟上篇文章一样,我们先实现纯净的Linux C++版本,然后再把代码移植到ROS的节点中。

在C++中怎么共享内存?

实现Linux进程间的内存共享,主要参考这篇文章

写进程

“写”进程,流程如下:

  1. 获得key, ftok()

  2. 使用key来创建一个共享内存 shmget()

  3. 映射共享内存(得到虚拟地址), shmat()

  4. 使用共享内存, 往共享内存中写入数据

  5. 解除映射 shmdt()

  6. 如果共享内存不再使用,可以使用shmctl()销毁共享内存

代码如下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h> 

int main()
{    // 生成一个key
    key_t key = ftok("./", 66);
    // 创建共享内存,返回一个id
    int shmid = shmget(key, 8, IPC_CREAT|0666|IPC_EXCL);    
    if(-1 == shmid)    
    {        
        perror("shmget failed");        
        exit(1);    
    }    
    // 映射共享内存,得到虚拟地址    
    void *p = shmat(shmid, 0, 0);    
    if((void*)-1 == p)    
    {        
        perror("shmat failed");        
        exit(2);    
    }    
    // 写共享内存    
    int *pp = (int *)p;    
    *pp = 0x12345678;   
    *(pp + 1) = 0xffffffff;    
    // 解除映射    
    if(-1 == shmdt(p))    
    {        
        perror("shmdt failed");        
        exit(3);    
    }    
    printf("解除映射成功,点击回车销毁共享内存\n");    
    getchar();    
    // 销毁共享内存    
    if(-1 == shmctl(shmid, IPC_RMID, NULL))    
    {        
        perror("shmctl failed");        
        exit(4);    
    }    
    return 0;
}

读进程

“读”进程,流程如下:

  1. 获得key, ftok()

  2. 使用key来获得一个共享内存 shmget()

  3. 映射共享内存(得到虚拟地址), shmat()

  4. 使用共享内存, 读取共享内存中的数据

  5. 解除映射 shmdt()

代码如下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h> 
int main()
{    
    // 生成一个key
    key_t key = ftok("./", 66);    
    // 获取共享内存,返回一个id    
    int shmid = shmget(key, 0, 0);    
    if(-1 == shmid)    
    {        
         perror("shmget failed");        
         exit(1);    
    }    
    // 映射共享内存,得到虚拟地址    
    void *p = shmat(shmid, 0, 0);    
    if((void*)-1 == p)    
    {        
        perror("shmat failed");        
        exit(2);    
    }    
    // 读共享内存    
    int x = *(int *)p;    
    int y = *((int *)p + 1);    
    printf("从共享内存中都取了:0x%x 和 0x%x \n", x, y);    
    // 解除映射    
    if(-1 == shmdt(p))    
    {        
        perror("shmdt failed");        
        exit(3);    
    }    
    return 0;
}

将上述代码移植进ROS

创建writeshmInRos.cpp

#include <ros/ros.h>
#include <iostream>
#include "lcm/lcm-cpp.hpp"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h> 
int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_publisher");  
  ros::NodeHandle nh;   
  // 生成一个key  
  key_t key = ftok("./", 66);  
  // 创建共享内存,返回一个id  
  int shmid = shmget(key, 8, IPC_CREAT|0666|IPC_EXCL);  
  if(-1 == shmid)  
  {
        perror("shmget failed");      
        exit(1);  
  }  
  // 映射共享内存,得到虚拟地址  
  void *p = shmat(shmid, 0, 0);  
  if((void*)-1 == p)  
  {
        perror("shmat failed");      
        exit(2);  
  }  
  // 写共享内存  
  int *pp = (int *)p;  
  *pp = 0x12345678;  
  *(pp + 1) = 0xffffffff;  
  // 解除映射  
  if(-1 == shmdt(p))  
  {
        perror("shmdt failed");      
        exit(3);  
  }  
  printf("解除映射成功,点击回车销毁共享内存\n");  
  getchar();  
  // 销毁共享内存  
  if(-1 == shmctl(shmid, IPC_RMID, NULL))  
  {
        perror("shmctl failed");      
        exit(4);  
  }   
  ros::spinOnce();}

创建readshmInRos.cpp

#include <ros/ros.h>
#include <iostream>
#include "lcm/lcm-cpp.hpp"
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h> 
int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_publisher");  
  ros::NodeHandle nh;   
  // 生成一个key  
  key_t key = ftok("./", 66);  
  // 获取共享内存,返回一个id  
  int shmid = shmget(key, 0, 0);  
  if(-1 == shmid)  
  {
        perror("shmget failed");      
        exit(1);  
  }  
  // 映射共享内存,得到虚拟地址  
  void *p = shmat(shmid, 0, 0);  
  if((void*)-1 == p)  
  {
        perror("shmat failed");      
        exit(2);  
  }  
  // 读共享内存  
  int x = *(int *)p;  
  int y = *((int *)p + 1);  
  printf("从共享内存中都取了:0x%x 和 0x%x \n", x, y);  
  // 解除映射  
  if(-1 == shmdt(p))  
  {
        perror("shmdt failed");      
        exit(3);  
  }   ros::spinOnce();
}

运行结果如下:
在这里插入图片描述
本文转载自:https://blog.csdn.net/weixinhum/article/details/84585954

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!