搜索
bottom↓
回复: 5

linux多进程如何访问同一块物理内存?

[复制链接]

出0入0汤圆

发表于 2020-6-18 09:02:10 | 显示全部楼层 |阅读模式


linux多进程如何访问同一块物理内存?

mmap将一个文件或者其它对象映射进内存,但是这个地址是虚拟地址,不同的进程mmap的地址是不一样的,我现在的需求是不同进程内存共享通信,且访问的地址一样。有没有方法可以实现?

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出30入25汤圆

发表于 2020-6-18 09:36:56 | 显示全部楼层
本帖最后由 shamiao 于 2020-6-18 09:40 编辑

“地址一致”——这是不可能做到的。

关于这一点,个人推荐看看 `boost::interprocess` 里边,共享内存里边放标准容器(vector、map等)是如何实现的,尤其是如何实现内存分配器(allocator)的。
一般来说,对于标准的STL容器,只需要传入一个类型作为分配器。也就是说这个分配器是不需要数据的,只需要代码。
但对于boost共享内存实现的容器,就必须传入一个符合boost约定的分配器的实例。这正是由于操作共享内存的时候,必须知道每个个别内存段的虚拟首地址、尺寸等额外信息,这是通过一个抽象类型做不到的。
也就是说,由于操作系统限制,boost::interprocess里的所有共享内存容器都不能通用STL的内存分配器。

——boost都做不到的东西,我觉得可以认为原理上不太可能,是不是就不值得尝试了 XD

出0入0汤圆

发表于 2020-6-18 09:38:32 | 显示全部楼层
共享内存有一个key的,不同进程可以用同一个key去访问同一片共享内存。

出0入0汤圆

发表于 2020-6-18 10:06:48 | 显示全部楼层
mmap操作荔枝派gpio v3s Linux
转至https://blog.csdn.net/diqiyong3212/article/details/102053091
1.预备知识

https://baike.baidu.com/item/mmap/1322217?fr=aladdin 大家直接看百度百科,比较清楚了。

2.代码

gpio.c

#include "gpio.h"

unsigned int fd;
PIO_Map *PIO = NULL;
unsigned int *gpio_map;
unsigned int addr_start, addr_offset;
unsigned int PageSize, PageMask;
void GPIO_Init(void)
{

    if ((fd = open("/dev/mem", O_RDWR)) == -1)
    {
        printf("open error\r\n");
        return;
    }

    PageSize = sysconf(_SC_PAGESIZE); //使用sysconf查询系统页面大小
    PageMask = (~(PageSize - 1));     //页掩码
    printf("PageSize:%d,PageMask:0x%.8X\r\n", PageSize, PageMask);

    addr_start = PIO_BASE_ADDRESS & PageMask;   //0x01C20800 & 0xfffff000 =  0x1C20000
    addr_offset = PIO_BASE_ADDRESS & ~PageMask; //0x01C20800 & 0x00000100 = 0x800
    printf("addr_start:%.8X,addr_offset:0x%.8X\r\n", addr_start, addr_offset);
    //mmap(系统自动分配内存地址,映射区长度“内存页的整数倍”,选择可读可写,MAP_SHARED=与其他所有映射到这个对象的进程共享空间,文件句柄,被映射内容的起点)
    //offest 映射物理内存的话,必须页对其!!!   所以这个起始地址应该是0x1000的整数倍,那么明显0x01C20800需要减去0x800才是整数倍!
    if ((gpio_map = mmap(NULL, PageSize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr_start)) == NULL)
    {
        printf("mmap error\r\n");
        close(fd);
        return;
    }
    printf("gpio_map:%.8X\r\n", gpio_map);
    //这里已经将0x1c20000的地址映射到了内存中,但是我们需要的地址是0x01C20800,所以要再加上地址偏移量~
    PIO = (PIO_Map *)((unsigned int)gpio_map + addr_offset);
    printf("PIO:0x%.8X\r\n", PIO);

    close(fd); //映射好之后就可以关闭文件?
}

void GPIO_ConfigPin(PORT port, unsigned int pin, PIN_MODE mode)
{
    if (gpio_map == NULL)
        return;
    PIO->Pn[port].CFG[pin / 8] &= ~((unsigned int)0x07 << pin % 8 * 4);
    PIO->Pn[port].CFG[pin / 8] |= ((unsigned int)mode << pin % 8 * 4);
    printf("struct PIO_Struct size : %d",sizeof(PIO->Pn[port]));
}

void GPIO_SetPin(PORT port, unsigned int pin, unsigned int level)
{
    if (gpio_map == NULL)
        return;
    if (level)
        PIO->Pn[port].DAT |= (1 << pin);
    else
        PIO->Pn[port].DAT &= ~(1 << pin);
}

int GPIO_Free(void)
{
    if ((munmap(gpio_map, PageSize * 2)) == 0)//取消映射
    {
        printf("unmap success!\r\n");
    }
    else
    {
        printf("unmap failed!\r\n");
    }
    return 0;
}
gpio.h

#ifndef __GPIO_H__
#define __GPIO_H__
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define PIO_BASE_ADDRESS 0x01C20800


//unsigned int 4字节 一个PIO_Struct占36字节,对应十六进制就是0x24,正好是一个offset值。
typedef struct
{
    unsigned int CFG[4];
    unsigned int DAT;
    unsigned int DRV0;
    unsigned int DRV1;
    unsigned int PUL0;
    unsigned int PUL1;
} PIO_Struct;

typedef struct
{
    PIO_Struct Pn[7];
} PIO_Map;

typedef enum {
    PA = 0,
    PB = 1,
    PC = 2,
    PD = 3,
    PE = 4,
    PF = 5,
    PG = 6,
} PORT;

typedef enum {
    IN = 0x00,
    OUT = 0x01,
    AUX = 0x02,
    INT = 0x06,
    DISABLE = 0x07,
} PIN_MODE;

extern PIO_Map *PIO;

void GPIO_Init(void);
void GPIO_ConfigPin(PORT port, unsigned int pin, PIN_MODE mode);
void GPIO_SetPin(PORT port, unsigned int pin, unsigned int level);
unsigned int GPIO_GetPin(PORT port, unsigned int pin);
int GPIO_Free(void);
#endif
main.c

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "gpio.h"
#include <stdbool.h>
int main()
{
    int a=0,b=-1,i;
    GPIO_Init();
    GPIO_ConfigPin(PB,4,OUT);
    GPIO_ConfigPin(PB,5,OUT);
    for(i=0;i<20;i++)
    {
        GPIO_SetPin(PB,4,a=~a);//!!-1的取反是0 1的取反是-2....
        GPIO_SetPin(PB,5,b=~b);
        //usleep(100000);
        sleep(1);
    }
    GPIO_Free();
}
makefile

TARGET        = myGPIO    #可执行文件名称

########################编译参数############################
CC            = arm-linux-gnueabihf-gcc
CXX           = arm-linux-gnueabihf-g++
DEFINES       =
CFLAGS        = -pipe -g -Wall -W -fPIE $(DEFINES)
CXXFLAGS      = -pipe -g -Wall -W -fPIE $(DEFINES)
INCPATH       = -I.


########################编译文件############################
SOURCES       = ./main.c ./gpio.c
OBJECTS       = main.o gpio.o

$(TARGET) : $(OBJECTS)
        $(CC) -o $(TARGET) $(OBJECTS)
main.o : main.c gpio.h
        $(CC) $(include) $(CFLAGS) -c main.c
gpio.o : gpio.c gpio.h
        $(CC) $(include) $(CFLAGS) -c gpio.c
clean :
        rm  $(OBJECTS) $(TARGET)
3.运行

将程序编译出来放到v3s上运行,那么pb4 pb5 会交替高低电平。

出0入0汤圆

 楼主| 发表于 2020-6-18 11:02:57 | 显示全部楼层
zzm24 发表于 2020-6-18 10:06
mmap操作荔枝派gpio v3s Linux
转至https://blog.csdn.net/diqiyong3212/article/details/102053091
1.预备 ...



不同进程 或 同一进程mmap 后  gpio_map地址都是变化的, 我的需求是不同进程 gpio_map地址不变!

出715入1076汤圆

发表于 2020-6-18 11:03:50 | 显示全部楼层
本帖最后由 dukelec 于 2020-6-18 11:06 编辑

我之前寫了一個 共享內存 通訊的小工具,你可以參考一下代碼: https://github.com/dukelec/cdipc

如果要操作物理地址,可以直接操作 /dev/mem 節點。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 09:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表