[英]How to properly share polymorphic data created at runtime between different cores? Embedded c++
我正在使用雙核設備,並且需要核心 A 創建一個包含 arguments 的數據結構,以獲取在核心 B 上運行的功能列表,定期更新它並通知核心 B。 arguments 的數量和類型可以更改在運行期間。
我的計划如下..
創建一個ParamsInterface
基礎 class 並且每個 function 都有自己的參數 class 派生自基礎 ZA2F2ED4F8EBC2CBB1。 使用多態性,這將允許我在共享 memory 中創建ParamsInterface*
的向量,並從核心 A 填充它。
核心 A 通過new
填充它需要的任何子 class 填充向量,並將返回的指針推送到向量。
示例核心 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 應該能夠靜態地將指針轉換為子類型,因為它知道向量的每個成員將是哪種類型。 當然訪問是由硬件信號量控制的,所有指針在刷新列表之前都會被刪除。
核心 B 示例:
void process(ParamsInterface* params)
{
Function1Params paramsCasted = static_cast<Function1Params *>(params);
processFunc1(paramsCasted->mParam1, paramsCasted->mParam2);
}
問題是當核心 B 讀取這個共享的、未緩存的數據時,ParamsInterface* 指向的地址不正確,並且在嘗試強制轉換時遇到了硬錯誤。 我檢查了 Core A 創建的指針,它指向兩個內核都可以訪問的 memory 區域。
我的問題有兩個方面,首先,我在這里做錯了什么-也許期望一種永遠行不通的方法起作用? 其次,我是否錯過了更好的方法來做到這一點? 我遺漏了有關函數列表如何工作以嘗試保持問題簡潔的信息。
非常感謝您的幫助。
編輯:
因此,問題似乎與創建 ParamsInterface 對象的位置有關。 核心 A 創建它們並將它們放置在堆中,不幸的是,它恰好位於不在托管的區域中,而核心 B 顯然無法訪問。
如果我使用placement new
將它們放置在memory 的托管部分中,我必須指定一個精確的地址,但這會變得非常復雜,因為所有ParamsInterface 對象的大小都可能不同。
那么有沒有辦法將 new() '多態'對象放入特定 memory 部分中的容器中? 還是我需要編寫某種自定義 memory 池管理器?
謝謝
從非常類似於 C 的角度來看,您似乎正在接近 C++ 代碼。 它們不僅在語法上是非常不同的野獸。
C++ 代碼是獨立解釋的,與硬件上下文無關,編譯器沒有義務尊重您編寫的內容,除了確保維護代碼產生的副作用。 這被稱為假設規則。
這擴展到多線程和多進程環境中的 memory 訪問。 除非另有說明,否則編譯器可以假設 memory 只會被他們正在編譯的代碼更改和讀取,並且不涉及外部因素。
這是一個具體的例子:
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
數組甚至不再存在! 見神螺栓
牢記這一點,以下內容:
當然訪問是由硬件信號量控制的。
是不足夠的。 C++ 語言不知道這些,跨線程/內核的對象之間的同步必須在語言級別以及硬件級別完成。 如果您不這樣做,則允許編譯器對 memory 的使用方式做出各種假設,並且會優化很多東西。
有兩種方法可以解決這個問題:
std::atomic_thread_fence
可能是您在這里需要的。 見神螺栓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
,以便編譯器停止對其何時以及如何更改進行假設。 見神螺栓volatile int* sharedParams[12] __attribute__((section(".shared_memory")));
void populate()
{
int volatile * params = new volatile int{12};
sharedParams[4] = params;
}
第一種選擇是非常可取的。 雖然它不像每次訪問時都設置完整的 memory 屏障那么殘酷,但后者會嚴重束縛編譯器的雙手。 volatile
也不保證事情會以正確的順序發生。
進一步閱讀: https://en.cppreference.com/w/cpp/atomic/memory_order
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.