gpt4 book ai didi

c++ - 如何在不同内核之间正确共享运行时创建的多态数据?嵌入式 C++

转载 作者:行者123 更新时间:2023-12-04 03:24:46 26 4
gpt4 key购买 nike

我正在使用双核设备,并且要求核心 A 创建一个数据结构,其中包含在核心 B 上运行的函数列表的参数,定期更新它并通知核心 B。参数和类型的数量可以改变在运行期间。
我的计划如下..
创建一个 ParamsInterface基类和每个函数都有它自己的从基类派生的参数类。使用多态性,这将允许我创建一个 vector ParamsInterface*在共享内存中,并从核心 A 填充它。
核心 A 通过 new 填充 vector 调用它需要的任何子类,并将返回的指针推送到 vector 。
示例核心 A:

volatile std::vector<ParamsInterface*> sharedParams __attribute__((section(".shared_memory")))

class ParamsInterface
{
public:
virtual ~ParamsInterface(){};
};

class Function1Params: public ParamsInterface
{
public:
float mParam1;
bool mParam2;
};


void populate()
{
Function1Params *params = new Function1Params ;
params->mParam1= 1.1;
params->mParam2 = true;
sharedParams.push_back(params);
}
然后核心 B 应该能够将指针静态地转换为子类型,因为它知道 vector 的每个成员将是哪种类型。当然访问是由硬件信号量控制的,在刷新列表之前删除所有指针。
示例核心 B:
void process(ParamsInterface* params)
{
Function1Params paramsCasted = static_cast<Function1Params *>(params);
processFunc1(paramsCasted->mParam1, paramsCasted->mParam2);
}
问题是,当核心 B 读取这个共享的、未缓存的数据时,ParamsInterface* 指向的地址不正确,我在尝试强制转换时遇到了硬错误。我检查了核心 A 创建的指针,它指向两个核心都可以访问的内存区域。
我的问题有两个方面,首先,我在这里做错了什么——也许期待一种永远无法奏效的方法?其次,我是否错过了更好的方法来做到这一点?我省略了有关函数列表如何工作的信息,以尽量保持问题简洁。
非常感谢您的帮助。
编辑:
因此,问题似乎与创建 ParamsInterface 对象的位置有关。核心 A 创建它们并将它们放置在堆中,不幸的是,这恰好位于不在托管的区域中,而核心 B 显然无法访问。
如果我使用展示位置 new要将它们放在内存的托管部分,我必须指定一个精确的地址,但这会变得非常复杂,因为所有的 ParamsInterface 对象都可能具有不同的大小。
那么有没有办法将 new() '多态' 对象放入特定内存部分的容器中?还是我需要编写某种自定义内存池管理器?
谢谢

最佳答案

您似乎是从一个非常类似于 C 的角度来处理 C++ 代码。它们不仅仅是语法上的非常不同的野兽。
C++ 代码是独立解释的,不受硬件上下文的影响,除了确保维护代码产生的副作用之外,编译器没有义务尊重您编写的内容。这被称为 as-if 规则。
这扩展到多线程和多进程环境中的内存访问。除非另有说明,否则编译器可以假设内存只会被他们正在编译的代码更改和读取,并且不涉及任何外部因素。
这是一个具体的例子:

int* sharedParams[12] __attribute__((section(".shared_memory")));

void populate()
{
auto params = new int{12};
sharedParams[4] = params;
}

int main() {
populate();

while(1) {}
}
如果我用 gcc -O3 -flto 编译它,我得到以下程序:
 jmp    401020 <main>
cs nop WORD PTR [rax+rax*1+0x0]
nop DWORD PTR [rax+0x0]
sharedParams数组甚至不存在了! see on godbolt
牢记这一点,以下几点:

Of course access is controlled by hardware semaphore.


是不足够的。 C++,语言,不知道这些,跨线程/内核的对象之间的同步必须在语言级别和硬件级别完成。如果你不这样做,编译器就可以对内存的使用方式做出各种假设,并且会优化很多东西。
有两种方法可以解决这个问题:
  • 使用语言级别的构造,例如标准库中存在的各种实用程序。 std::atomic_thread_fence可能是你在这里需要的。 See on godbolt

  • void populate() 
    {
    int* params = new int{12};
    sharedParams[4] = params;
    std::atomic_thread_fence( std::memory_order_release ); // std::memory_order_acquire when reading
    }
    注意 std::atomic_thread_fence 并不是真的很适合这个用例,但因为你已经在语言范围之外操作了。它应该符合这里的要求,但不会有正式的保证。
  • 将有争议的内存标记为 volatile以便编译器停止对何时以及如何更改进行假设。 See on godbolt

  • volatile int* sharedParams[12] __attribute__((section(".shared_memory")));
    void populate()
    {
    int volatile * params = new volatile int{12};
    sharedParams[4] = params;
    }
    第一个选项非常可取。虽然它不像每次访问时都设置满内存屏障那样残酷,但后者会严重束缚编译器的手。 volatile也不保证事情会按正确的顺序发生。
    进一步阅读: https://en.cppreference.com/w/cpp/atomic/memory_order

    关于c++ - 如何在不同内核之间正确共享运行时创建的多态数据?嵌入式 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67780227/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com