256 lines
6.5 KiB
C++
Executable File
256 lines
6.5 KiB
C++
Executable File
/**
|
||
* @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"
|
||
#include "XNModelManager.h"
|
||
|
||
// 默认构造函数
|
||
XNThreadManager::XNThreadManager(QObject *parent)
|
||
: XNBaseFrameObject(*new XNThreadManagerPrivate(this), parent)
|
||
{
|
||
setUniqueId(3);
|
||
setObjectName("XNThreadManager");
|
||
}
|
||
|
||
XNThreadManager::~XNThreadManager()
|
||
{
|
||
}
|
||
|
||
XNThreadManager::XNThreadManager(XNThreadManagerPrivate &dd, QObject *parent)
|
||
: XNBaseFrameObject(dd, parent)
|
||
{
|
||
}
|
||
|
||
// 初始化函数
|
||
void XNThreadManager::OnInitialize()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
d->_eRunStatus = RunStatus::NotStart;
|
||
LOG_INFO("XNThreadManager Initialize Success!");
|
||
d->_status = XNFrameObjectStatus::Initialized;
|
||
emit Initialize();
|
||
}
|
||
|
||
// 开始控制
|
||
void XNThreadManager::OnStart()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
// 如果当前状态是未开始状态
|
||
if (d->_eRunStatus == RunStatus::NotStart) {
|
||
// 状态切换为正在运行
|
||
d->_eRunStatus = RunStatus::Runing;
|
||
}
|
||
}
|
||
|
||
// 停止控制
|
||
void XNThreadManager::OnAbort()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
// 如果当前状态不是停止状态
|
||
if (d->_eRunStatus != RunStatus::Aborted) {
|
||
// 状态切换为停止
|
||
d->_eRunStatus = RunStatus::Aborted;
|
||
}
|
||
}
|
||
|
||
// 暂停控制
|
||
void XNThreadManager::OnPause()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
// 如果当前是正在运行状态
|
||
if (d->_eRunStatus == RunStatus::Runing) {
|
||
// 状态切换为暂停
|
||
d->_eRunStatus = RunStatus::Suspend;
|
||
}
|
||
}
|
||
|
||
// 继续控制
|
||
void XNThreadManager::OnContinue()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
// 如果当前是暂停状态
|
||
if (d->_eRunStatus == RunStatus::Suspend) {
|
||
//TODO 这里需要重新设置一下时间信息,不然启动后会加速运行至设定的时间
|
||
// 状态切换为正在运行
|
||
d->_eRunStatus = RunStatus::Runing;
|
||
}
|
||
}
|
||
|
||
// 获取当前运行状态
|
||
RunStatus XNThreadManager::GetStatus()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
return d->_eRunStatus;
|
||
}
|
||
|
||
// 添加周期性函数
|
||
void XNThreadManager::OnRegisterFunction(quint32 id, XNCallBack fun, quint32 freqGroup,
|
||
quint32 RunPos, quint32 RunPriorty)
|
||
{
|
||
Q_D(XNThreadManager);
|
||
// 如果周期性函数校验通过
|
||
if (IsFunParamRight(id, freqGroup, RunPos)) {
|
||
// 存储提交的函数
|
||
funInfoPtr sFunInfo = funInfoPtr::create();
|
||
sFunInfo->fun = fun;
|
||
sFunInfo->freqGroup = freqGroup;
|
||
sFunInfo->RunPos = RunPos;
|
||
sFunInfo->RunPriority = RunPriorty;
|
||
d->funList[id].push_back(sFunInfo);
|
||
// 加入线程任务池
|
||
auto threadPool = this->findChildren<XNThread *>();
|
||
for (auto thread : threadPool) {
|
||
if ((quint32)thread->GetRunFrequecy() == freqGroup) {
|
||
thread->AddFunction(fun, (FreqLevel)freqGroup, RunPos, RunPriorty);
|
||
break;
|
||
}
|
||
}
|
||
LOG_INFO("Model [ %1] register periodic function success! Run node: %2-%3 Priority: %4", id,
|
||
freqGroup, RunPos, RunPriorty);
|
||
}
|
||
}
|
||
|
||
// 注册函数校验
|
||
bool XNThreadManager::IsFunParamRight(quint32 id, quint32 freqGroup, quint32 RunPos)
|
||
{
|
||
quint32 ufreq = freqGroup;
|
||
// 检查提交的函数是否符合规定
|
||
if (ufreq < 0 || ufreq > 5) {
|
||
// 如果频率分组不是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;
|
||
} else if (RunPos > pow(2, freqGroup)) {
|
||
// 如果运行节点不符合要求
|
||
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;
|
||
}
|
||
|
||
// 仿真运行前做最后处理
|
||
void XNThreadManager::OnPrepareForExecute()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
PERIOD_INFO pinfo;
|
||
clock_gettime(CLOCK_MONOTONIC, &(pinfo.next_period));
|
||
emit SetStartTime(pinfo.next_period);
|
||
// 所有线程初始化
|
||
LOG_INFO("XNThreadManager is preparing...");
|
||
auto threadPool = this->findChildren<XNThread *>();
|
||
for (auto &thread : threadPool) {
|
||
bool bRet = thread->Initialize();
|
||
if (!bRet) {
|
||
emit PrepareForExecuteFailed();
|
||
return;
|
||
}
|
||
}
|
||
d->_status = XNFrameObjectStatus::Ready;
|
||
// 通知模型管理器进行最后准备
|
||
LOG_INFO("XNThreadManager is prepared!");
|
||
emit PrepareForExecute();
|
||
}
|
||
|
||
// 添加线程
|
||
void XNThreadManager::OnAddThreadPool(QString name, FreqLevel freq, quint32 priority,
|
||
quint32 CPUAff, double RunInter)
|
||
{
|
||
Q_D(XNThreadManager);
|
||
// 创建线程对象
|
||
XNThread *thread = new XNThread(this, name, freq, priority, CPUAff, RunInter);
|
||
// 连接信号和槽
|
||
//connect(this, &XNThreadManager::SetRunInter, thread, &XNThread::SetRunInter);
|
||
connect(this, &XNThreadManager::SetStartTime, thread, &XNThread::OnSetStartTime);
|
||
connect(this, &XNThreadManager::SimControl, thread, &XNThread::OnSimControl);
|
||
thread->SetThreadID(AllocateThreadID());
|
||
LOG_INFO("Add Thread Success, Frequency: %1 Hz, Interval: %2 ns.",
|
||
d->dRunFreq / pow(2, (quint32)freq), RunInter);
|
||
d->threadCount++;
|
||
}
|
||
|
||
void XNThreadManager::OnSimControl(quint32 objectId, SimControlCmd cmd)
|
||
{
|
||
if (objectId == 0) {
|
||
switch (cmd) {
|
||
case SimControlCmd::Start:
|
||
OnStart();
|
||
break;
|
||
case SimControlCmd::Abort:
|
||
OnAbort();
|
||
break;
|
||
case SimControlCmd::Continue:
|
||
OnContinue();
|
||
break;
|
||
case SimControlCmd::Suspend:
|
||
OnPause();
|
||
break;
|
||
}
|
||
}
|
||
emit SimControl(objectId, cmd);
|
||
}
|
||
|
||
// 设置模型运行基频
|
||
void XNThreadManager::OnSetBaseFreq(const double &dBaseFreq)
|
||
{
|
||
Q_D(XNThreadManager);
|
||
d->dRunFreq = dBaseFreq;
|
||
d->dRunInter = 1.0e9 / dBaseFreq;
|
||
//emit SetRunInter(d->dRunInter);
|
||
LOG_INFO("Set engine base run frequency to %1 Hz, interval: %2 ns.", d->dRunFreq, d->dRunInter);
|
||
}
|
||
|
||
// 获得模型运行基频
|
||
const double &XNThreadManager::GetBaseFreq()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
return d->dRunFreq;
|
||
}
|
||
|
||
// 获得模型运行基础间隔
|
||
const double &XNThreadManager::GetBaseInter()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
return d->dRunInter;
|
||
}
|
||
|
||
// 通过运行间隔设置基频
|
||
void XNThreadManager::SetBaseFreqByInter(const double &dBaseInter)
|
||
{
|
||
Q_D(XNThreadManager);
|
||
d->dRunFreq = 1.0e9 / dBaseInter;
|
||
d->dRunInter = dBaseInter;
|
||
LOG_INFO("Set engine base run frequency to %1 Hz, interval: %2 ns.", d->dRunFreq, d->dRunInter);
|
||
}
|
||
|
||
// 获取线程数量
|
||
quint32 XNThreadManager::GetThreadCount()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
return d->threadCount;
|
||
}
|
||
|
||
// 分配线程ID
|
||
quint32 XNThreadManager::AllocateThreadID()
|
||
{
|
||
Q_D(XNThreadManager);
|
||
//从5000到9999分配线程ID
|
||
static quint32 threadID = 5000;
|
||
while (d->threadIDMap.contains(threadID)) {
|
||
threadID++;
|
||
}
|
||
d->threadIDMap.insert(threadID);
|
||
return threadID;
|
||
}
|