2025-04-28 12:25:20 +08:00
|
|
|
|
/**
|
|
|
|
|
* @file XNThreadManager.cpp
|
|
|
|
|
* @author jinchao
|
|
|
|
|
* @brief 线程管理器类源文件
|
|
|
|
|
* @version 1.0
|
|
|
|
|
* @date 2024-11-07
|
|
|
|
|
*
|
|
|
|
|
* @copyright Copyright (c) 2024 XN
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
#include "XNThreadManager.h"
|
|
|
|
|
#include "XNThreadManager_p.h"
|
|
|
|
|
#include "XNFramework.h"
|
2025-05-20 15:39:40 +08:00
|
|
|
|
#include "XNTimeManager.h"
|
2025-04-28 12:25:20 +08:00
|
|
|
|
#include "XNModelManager.h"
|
|
|
|
|
|
|
|
|
|
// 默认构造函数
|
2025-05-20 15:39:40 +08:00
|
|
|
|
XNThreadManager::XNThreadManager() : XNBaseFrameObject(new XNThreadManagerPrivate())
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
SetUniqueId(3);
|
|
|
|
|
SetObjectName("XNThreadManager");
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XNThreadManager::~XNThreadManager()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-20 15:39:40 +08:00
|
|
|
|
XNThreadManager::XNThreadManager(PrivateType *p) : XNBaseFrameObject(p)
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化函数
|
2025-05-20 15:39:40 +08:00
|
|
|
|
bool XNThreadManager::Initialize()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
d->_eRunStatus = RunStatus::NotStart;
|
2025-05-20 15:39:40 +08:00
|
|
|
|
d->threadList.clear();
|
|
|
|
|
d->funList.clear();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
LOG_INFO("XNThreadManager Initialize Success!");
|
|
|
|
|
d->_status = XNFrameObjectStatus::Initialized;
|
2025-05-20 15:39:40 +08:00
|
|
|
|
return true;
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 开始控制
|
2025-05-20 15:39:40 +08:00
|
|
|
|
void XNThreadManager::Start()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 如果当前状态是未开始状态
|
|
|
|
|
if (d->_eRunStatus == RunStatus::NotStart) {
|
|
|
|
|
// 状态切换为正在运行
|
|
|
|
|
d->_eRunStatus = RunStatus::Runing;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 停止控制
|
2025-05-20 15:39:40 +08:00
|
|
|
|
void XNThreadManager::Abort()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 如果当前状态不是停止状态
|
|
|
|
|
if (d->_eRunStatus != RunStatus::Aborted) {
|
|
|
|
|
// 状态切换为停止
|
|
|
|
|
d->_eRunStatus = RunStatus::Aborted;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 暂停控制
|
2025-05-20 15:39:40 +08:00
|
|
|
|
void XNThreadManager::Pause()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 如果当前是正在运行状态
|
|
|
|
|
if (d->_eRunStatus == RunStatus::Runing) {
|
|
|
|
|
// 状态切换为暂停
|
|
|
|
|
d->_eRunStatus = RunStatus::Suspend;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 继续控制
|
2025-05-20 15:39:40 +08:00
|
|
|
|
void XNThreadManager::Continue()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 如果当前是暂停状态
|
|
|
|
|
if (d->_eRunStatus == RunStatus::Suspend) {
|
|
|
|
|
//TODO 这里需要重新设置一下时间信息,不然启动后会加速运行至设定的时间
|
|
|
|
|
// 状态切换为正在运行
|
|
|
|
|
d->_eRunStatus = RunStatus::Runing;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取当前运行状态
|
|
|
|
|
RunStatus XNThreadManager::GetStatus()
|
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
return d->_eRunStatus;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加周期性函数
|
2025-05-20 15:39:40 +08:00
|
|
|
|
void XNThreadManager::RegisterFunction(uint32_t id, XNCallBack fun, uint32_t threadID,
|
|
|
|
|
uint32_t freqGroup, uint32_t RunPos, uint32_t RunPriorty)
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 如果周期性函数校验通过
|
|
|
|
|
if (IsFunParamRight(id, freqGroup, RunPos)) {
|
|
|
|
|
// 存储提交的函数
|
2025-05-20 15:39:40 +08:00
|
|
|
|
funInfoPtr sFunInfo = std::make_shared<funInfo>();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
sFunInfo->fun = fun;
|
2025-05-20 15:39:40 +08:00
|
|
|
|
sFunInfo->threadID = threadID;
|
2025-04-28 12:25:20 +08:00
|
|
|
|
sFunInfo->freqGroup = freqGroup;
|
|
|
|
|
sFunInfo->RunPos = RunPos;
|
|
|
|
|
sFunInfo->RunPriority = RunPriorty;
|
|
|
|
|
d->funList[id].push_back(sFunInfo);
|
2025-05-20 15:39:40 +08:00
|
|
|
|
if (d->threadList.find(threadID) != d->threadList.end()) {
|
|
|
|
|
d->threadList[threadID]->AddFunction(fun, (FreqLevel)freqGroup, RunPos, RunPriorty);
|
|
|
|
|
LOG_INFO("Model [ %1] register periodic function success! Run node: %2-%3 Priority: %4",
|
|
|
|
|
id, freqGroup, RunPos, RunPriorty);
|
|
|
|
|
} else {
|
|
|
|
|
LOG_ERROR("0x2172 The thread [ %1 ] does not exist, registration failed!", threadID);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 注册函数校验
|
2025-05-20 15:39:40 +08:00
|
|
|
|
bool XNThreadManager::IsFunParamRight(uint32_t id, uint32_t freqGroup, uint32_t RunPos)
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
|
|
|
|
// 检查提交的函数是否符合规定
|
2025-05-20 15:39:40 +08:00
|
|
|
|
if (freqGroup < 0 || freqGroup > 5) {
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 如果频率分组不是0~5
|
|
|
|
|
LOG_WARNING("0x2170 The submitted function's run frequency group of Model [ %1 ] is not "
|
|
|
|
|
"between 0 and 5, registration failed!",
|
|
|
|
|
id);
|
|
|
|
|
return false;
|
2025-05-20 15:39:40 +08:00
|
|
|
|
} else if (RunPos > (1 << freqGroup)) {
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 如果运行节点不符合要求
|
|
|
|
|
LOG_WARNING("0x2171 The run node submitted for registration by model [ %1 ] exceeds the "
|
|
|
|
|
"maximum node count for the frequency group, registration failed!",
|
|
|
|
|
id);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 仿真运行前做最后处理
|
2025-05-20 15:39:40 +08:00
|
|
|
|
bool XNThreadManager::PrepareForExecute()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
PERIOD_INFO pinfo;
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &(pinfo.next_period));
|
2025-05-20 15:39:40 +08:00
|
|
|
|
for (auto &thread : d->threadList) {
|
|
|
|
|
thread.second->SetStartTime(pinfo.next_period);
|
|
|
|
|
}
|
|
|
|
|
//设置开始事件
|
|
|
|
|
auto framework = GetFramework();
|
|
|
|
|
if (framework) {
|
|
|
|
|
auto timeManager = framework->GetTimeManager();
|
|
|
|
|
if (timeManager) {
|
|
|
|
|
timeManager->SetStartTime(pinfo.next_period);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 所有线程初始化
|
|
|
|
|
LOG_INFO("XNThreadManager is preparing...");
|
2025-05-20 15:39:40 +08:00
|
|
|
|
for (auto &thread : d->threadList) {
|
|
|
|
|
bool bRet = thread.second->Initialize();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
if (!bRet) {
|
2025-05-20 15:39:40 +08:00
|
|
|
|
LOG_ERROR("Thread [ %1 ] PrepareForExecute Failed!", thread.first);
|
|
|
|
|
continue;
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
d->_status = XNFrameObjectStatus::Ready;
|
|
|
|
|
LOG_INFO("XNThreadManager is prepared!");
|
2025-05-20 15:39:40 +08:00
|
|
|
|
return true;
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加线程
|
2025-05-20 15:39:40 +08:00
|
|
|
|
uint32_t XNThreadManager::AddThreadPool(std::string name, double freq, uint32_t priority,
|
|
|
|
|
uint32_t CPUAff)
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
// 创建线程对象
|
2025-05-20 15:39:40 +08:00
|
|
|
|
XNThreadPtr thread = std::make_shared<XNThread>(name, freq, priority, CPUAff);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
thread->SetThreadID(AllocateThreadID());
|
2025-05-22 09:20:04 +08:00
|
|
|
|
thread->SetFramework(GetFramework());
|
2025-05-20 15:39:40 +08:00
|
|
|
|
LOG_INFO("Add Thread Success, Frequency: %1 Hz, Interval: %2 ns.", freq, 1.0e9 / freq);
|
|
|
|
|
d->threadList[thread->GetThreadID()] = thread;
|
|
|
|
|
return thread->GetThreadID();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-20 15:39:40 +08:00
|
|
|
|
void XNThreadManager::SimControl(uint32_t objectId, SimControlCmd cmd)
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
if (objectId == 0) {
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case SimControlCmd::Start:
|
2025-05-20 15:39:40 +08:00
|
|
|
|
Start();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
break;
|
|
|
|
|
case SimControlCmd::Abort:
|
2025-05-20 15:39:40 +08:00
|
|
|
|
Abort();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
break;
|
|
|
|
|
case SimControlCmd::Continue:
|
2025-05-20 15:39:40 +08:00
|
|
|
|
Continue();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
break;
|
|
|
|
|
case SimControlCmd::Suspend:
|
2025-05-20 15:39:40 +08:00
|
|
|
|
Pause();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-20 15:39:40 +08:00
|
|
|
|
for (auto &thread : d->threadList) {
|
|
|
|
|
thread.second->SimControl(objectId, cmd);
|
|
|
|
|
}
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取线程数量
|
2025-05-20 15:39:40 +08:00
|
|
|
|
uint32_t XNThreadManager::GetThreadCount()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
|
|
|
|
return d->threadList.size();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 分配线程ID
|
2025-05-20 15:39:40 +08:00
|
|
|
|
uint32_t XNThreadManager::AllocateThreadID()
|
2025-04-28 12:25:20 +08:00
|
|
|
|
{
|
2025-05-20 15:39:40 +08:00
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
|
//从5000到9999分配线程ID
|
2025-05-20 15:39:40 +08:00
|
|
|
|
static uint32_t threadID = 5000;
|
|
|
|
|
while (d->threadList.find(threadID) != d->threadList.end()) {
|
2025-04-28 12:25:20 +08:00
|
|
|
|
threadID++;
|
|
|
|
|
}
|
2025-05-20 15:39:40 +08:00
|
|
|
|
d->threadList[threadID] = nullptr;
|
2025-04-28 12:25:20 +08:00
|
|
|
|
return threadID;
|
|
|
|
|
}
|
2025-05-21 12:17:50 +08:00
|
|
|
|
|
|
|
|
|
void XNThreadManager::SetThreadFreqByID(uint32_t threadID, double freq)
|
|
|
|
|
{
|
|
|
|
|
T_D();
|
|
|
|
|
d->threadList[threadID]->SetRunFrequecy(freq);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double XNThreadManager::GetThreadFreqByID(uint32_t threadID)
|
|
|
|
|
{
|
|
|
|
|
T_D();
|
|
|
|
|
return d->threadList[threadID]->GetRunFrequecy();
|
|
|
|
|
}
|