完善后端析构逻辑以及优化日志性能

This commit is contained in:
2025-09-21 18:53:48 +08:00
parent f82af9201a
commit b1818e8fce
6 changed files with 161 additions and 272 deletions
@@ -1,216 +0,0 @@
#include <qthread.h>
#include <serviceManager.h>
#include <sql/qSqlBase.h>
#include <missionLoader.h>
#include <CLIManager.h>
#include <back/missionResultHandle.h>
#include <jsonRpcServer.h>
class detProcess : public QThread
{
public:
CsvWriter* _csvWriter = nullptr;
missionResultHandle* _missionResultHandle = nullptr;
ServiceManager _serviceManager;
CLIManager* _cliManager; // 命令行接口管理器
rpc::JsonRpcServer _rpcServer;
bool initOnce = false;
detProcess(SQLiteDB* dbIn, nlohmann::ordered_json& jsonIn, qtFuncBridge* bridgeIn):
db(dbIn),bridge(bridgeIn), missionJson(jsonIn){
}
// 对普通指针的安全删除
template<typename T>
void safeDelete(T*& ptr) {
if (ptr) { delete ptr; ptr = nullptr; }
}
// 尝试对基于 QThread 的 serviceModule 进行关停,然后删除
void safeShutdownDelete(serviceModule* ptr) {
if (!ptr) return;
// 如果对象正在运行,尝试停止
if (ptr->isRunning()) {
// 如果存在 stop 槽,则尝试调用
QMetaObject::invokeMethod(ptr, "stop", Qt::DirectConnection);
// 作为后备,尝试退出事件循环
QMetaObject::invokeMethod(ptr, "quit", Qt::DirectConnection);
// 等待其退出,给予一定时间
if (!ptr->wait(2000)) {
// 仍在运行时,作为最后手段强制终止
ptr->terminate();
ptr->wait(1000);
}
}
delete ptr; ptr = nullptr;
}
void init() {
// 创建/重建需要的服务模块,避免重复创建
if (!_serviceManager._imgSaveThreadManager) {
_serviceManager._imgSaveThreadManager = new imgSaveThreadManager(missionJson["imgSaveBasePath"]);
}
if (!_serviceManager._cameraManager) {
_serviceManager._cameraManager = new cameraManager(missionJson, bridge);
}
if (!_serviceManager._triggerManager) {
_serviceManager._triggerManager = new triggerManager(this, bridge, missionJson["Triggers"]);
}
if (initOnce == false) {
initOnce = true;
_csvWriter = new CsvWriter(db);
_serviceManager._detDataManager = new detDataManager();
_missionResultHandle = new missionResultHandle(bridge);
_serviceManager._missionResultHandle = _missionResultHandle;
_serviceManager.dataBase = db;
_serviceManager._csvWriter = _csvWriter;
// handleAiModelManager 与 CLI 等只在首次初始化创建
if (!_serviceManager._handleAiModelManager) {
_serviceManager._handleAiModelManager = new handleAiModelManager(missionJson, bridge);
}
connect(bridge, &qtFuncBridge::reInitConfig, this, [=]() {reinitConfig(); });
_cliManager = new CLIManager(&_serviceManager, bridge);
}
}
bool waitrForInitResult(serviceModule* ptr, int overtimeS = 999999) {
int overTimeMs = overtimeS * 1000;
int timecnt = 0;
while (timecnt <= overTimeMs) {
if (ptr->status != NotInit)
break;
QThread::msleep(100);
timecnt += 100;
}
if (timecnt > overTimeMs)
return false;
if (ptr->status == InitFailure)
return false;
return true;
}
// 重新初始化配置
void reinitConfig() {
// 停止并删除线程型模块
safeShutdownDelete(_serviceManager._cameraManager);
safeShutdownDelete(_serviceManager._triggerManager);
if (_serviceManager._handleAiModelManager) {
// try invoking stop if exists
QMetaObject::invokeMethod(_serviceManager._handleAiModelManager, "stop", Qt::DirectConnection);
safeDelete(_serviceManager._handleAiModelManager);
}
init();
if (!this->isRunning()) {
this->start();
} else {
qDebug() << "detProcess already running, init refreshed. run() should handle reloading if needed.";
}
}
// 初始化并运行主流程
void run() {
#if 1
_serviceManager._cameraManager->start();
_serviceManager._handleAiModelManager->start();
_serviceManager._triggerManager->start();
bool res1 = waitrForInitResult(_serviceManager._cameraManager);
bool res2 = waitrForInitResult(_serviceManager._handleAiModelManager);
bool res3 = waitrForInitResult(_serviceManager._triggerManager);
if (res1 == true && res2 == true && res3 == true) {
_missionLoader.loadMission(missionJson["missionDllPath"]);
_missionLoader.getmission(missionJson["missionDllPath"])->initBasic(
&_serviceManager,
missionJson["missionSettings"], bridge
);
_cliManager->initBasicPreset(_missionLoader.getmission(missionJson["missionDllPath"]));
_serviceManager._detDataManager->setTriggerManager(_serviceManager._triggerManager);
initJsonRpc();
emit bridge->initResult(InitOK);
}
else {
emit bridge->initResult(InitFailure);
}
#endif
}
void initJsonRpc() {
//QObject::connect(&_rpcServer, &JsonRpcServer::clientConnected,
// [](const QString& address) {
// qInfo() << "New client connected:" << address;
// });
//QObject::connect(&_rpcServer, &JsonRpcServer::requestReceived,
// [](const QString& method, const json& params, const QString& address) {
// qDebug() << "Request from" << address << "- Method:" << method;
// });
/* _rpcServer.registerMethod("getServerInfo", [](const json& params) -> json {
return json{
{"name", "JSON-RPC Server"},
{"version", "1.0.0"},
{"timestamp", QDateTime::currentSecsSinceEpoch()}
};
});*/
//_rpcServer.registerMethod("getMachineInfo", [](const json& params) -> json {
// auto& config = appConfig::getInstance();
// return json{
// {"name", config.softwareTile.c_str()},
// {"timestamp", QDateTime::currentSecsSinceEpoch()}
// };
// });
//_rpcServer.registerMethod("reloadConfig", [this](const json& params) -> json {
// _cliManager->cliCommand("reloadConfig");
// return json{
// {"result", "OK"} };
// });
//// 添加连接信号用于调试
//QObject::connect(&_rpcServer, &JsonRpcServer::clientConnected,
// [](const QString& address) {
// qInfo() << "RPC Client connected:" << address;
// });
//QObject::connect(&_rpcServer, &JsonRpcServer::clientDisconnected,
// [](const QString& address) {
// qInfo() << "RPC Client disconnected:" << address;
// });
//QObject::connect(&_rpcServer, &JsonRpcServer::requestReceived,
// [](const QString& method, const json& params, const QString& address) {
// qDebug() << "RPC Request from" << address << "- Method:" << method;
// });
//QObject::connect(&_rpcServer, &JsonRpcServer::errorOccurred,
// [](const QString& error, const QString& address) {
// qWarning() << "RPC Error from" << address << ":" << error;
// });
_rpcServer.registerMethod(QStringLiteral("reloadConfig"), [this](const nlohmann::json&) -> nlohmann::json {
_cliManager->cliCommand("reloadConfig");
std::cout << "接收到远程命令->重新加载配置文件" << std::endl;
return nlohmann::json{
{"result", "OK"}
};
});
// 检查服务器启动结果
_rpcServer.start(2367);
//if (_rpcServer.start(2367)) {
// qInfo() << "JSON-RPC server started successfully on port" << _rpcServer.serverPort();
//}
//else {
// qCritical() << "Failed to start JSON-RPC server on port 2367";
// // 尝试其他端口
// for (int port = 2368; port <= 2370; ++port) {
// if (_rpcServer.start(port)) {
// qInfo() << "JSON-RPC server started on alternative port" << port;
// break;
// }
// }
//}
}
private:
nlohmann::ordered_json missionJson;
SQLiteDB* db;
qtFuncBridge* bridge;
MissionLoader _missionLoader; // 任务加载器,用于加载任务配置
};
#pragma once
-1
View File
@@ -66,7 +66,6 @@ public:
~triggerManager(){
runFlag = false;
this->stop();
this->terminate();
delete trigger;
}
triggerManager(detProcess*, qtFuncBridge* bridgeIn, nlohmann::ordered_json& triggerJson);
+9 -3
View File
@@ -20,10 +20,16 @@ public:
}
void cleanup() override {
if (_detProcess != nullptr){
delete _detProcess;
_detProcess = nullptr;
}
}
~Backend() {
delete _detProcess;
if (_detProcess != nullptr) {
delete _detProcess;
_detProcess = nullptr;
}
}
bool excuteCliCommand(const QString& command) {
return _detProcess->_cliManager->cliCommand(command);
@@ -33,7 +39,7 @@ public:
}
private:
bool initOnce = false;
detProcess* _detProcess;
detProcess* _detProcess = nullptr;
qtFuncBridge* bridge = nullptr;
};
+5 -1
View File
@@ -18,7 +18,11 @@ public:
db(dbIn),bridge(bridgeIn), missionJson(jsonIn){
}
~detProcess() {
safeShutdownDelete(_serviceManager._triggerManager);
safeShutdownDelete(_serviceManager._cameraManager);
safeDelete(_serviceManager._handleAiModelManager);
}
// 对普通指针的安全删除
template<typename T>
void safeDelete(T*& ptr) {
+145 -50
View File
@@ -24,9 +24,16 @@
#include <QMessageBox>
#include <QRegularExpression>
#include <QTextCharFormat>
#include <QMutex>
#include <QMutexLocker>
#include <QTimer>
//行数上限
const int MAX_LOGWIDGET_LINES = 1000;
//内存中存储的消息数量上限
const int MAX_STORED_MESSAGES = 5000;
//批量处理延迟时间(毫秒)
const int BATCH_UPDATE_DELAY = 100;
class logWidget : public QWidget {
Q_OBJECT
@@ -45,9 +52,15 @@ private:
QPlainTextEdit* textWidget;
QStringList allMessages; // 存储所有原始消息
bool autoScroll = true;
mutable QMutex mutex; // 保护此状态的互斥锁
QStringList pendingMessages; // 待处理的消息队列
};
std::unordered_map<int, FilterState> filterStates;
// 线程安全和性能优化相关
mutable QMutex globalMutex; // 全局保护锁
QTimer* batchUpdateTimer; // 批量更新定时器
public:
QVBoxLayout* Layout;
@@ -63,6 +76,12 @@ public:
palette.setColor(QPalette::WindowText, Qt::white);
QFont font("微软雅黑", 24, QFont::Bold);
// 初始化批量处理定时器
batchUpdateTimer = new QTimer(this);
batchUpdateTimer->setSingleShot(false);
batchUpdateTimer->setInterval(BATCH_UPDATE_DELAY);
connect(batchUpdateTimer, &QTimer::timeout, this, &logWidget::processPendingMessages);
widgets = new QStackedWidget();
widgets->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -125,6 +144,9 @@ public:
btnPtr->toDefault();
btn->pressed();
widgets->setCurrentIndex(index);
// 切换页面时应用过滤器以显示最新内容
applyFilters(index);
});
QWidget* widget = new QWidget();
@@ -235,11 +257,67 @@ public:
}
private:
// 应用过滤器
void applyFilters(int index) {
// 线程安全地添加消息
void addMessageSafe(int index, const QString& message) {
QMutexLocker globalLocker(&globalMutex);
if (filterStates.find(index) == filterStates.end()) return;
FilterState& state = filterStates[index];
QMutexLocker stateLocker(&state.mutex);
// 限制消息数量,防止内存泄漏
if (state.allMessages.size() >= MAX_STORED_MESSAGES) {
// 删除最老的消息(前面的1/4)
int removeCount = MAX_STORED_MESSAGES / 4;
for (int i = 0; i < removeCount && !state.allMessages.isEmpty(); ++i) {
state.allMessages.removeFirst();
}
}
state.allMessages.append(message);
state.pendingMessages.append(message);
// 启动批量更新定时器
if (!batchUpdateTimer->isActive()) {
batchUpdateTimer->start();
}
}
// 批量处理待处理的消息
// 判断消息是否应该显示
bool shouldShowMessage(const QString& message, const FilterState& state) {
QString levelFilter = state.levelFilter->currentText();
QString regexPattern = state.regexFilter->text();
// 级别过滤
if (levelFilter != "全部") {
if (!message.contains(levelFilter, Qt::CaseInsensitive)) {
return false;
}
}
// 正则过滤
if (!regexPattern.isEmpty()) {
QRegularExpression regex(regexPattern);
if (regex.isValid() && !regex.match(message).hasMatch()) {
return false;
}
}
return true;
}
// 应用过滤器
void applyFilters(int index) {
QMutexLocker globalLocker(&globalMutex);
if (filterStates.find(index) == filterStates.end()) return;
FilterState& state = filterStates[index];
QMutexLocker stateLocker(&state.mutex);
QString levelFilter = state.levelFilter->currentText();
QString regexPattern = state.regexFilter->text();
@@ -247,6 +325,7 @@ private:
state.textWidget->clear();
QRegularExpression regex;
bool regexValid = true;
if (!regexPattern.isEmpty()) {
regex.setPattern(regexPattern);
if (!regex.isValid()) {
@@ -257,28 +336,15 @@ private:
// 过滤并显示消息
for (const QString& message : state.allMessages) {
bool shouldShow = true;
// 级别过滤
if (levelFilter != "全部") {
if (!message.contains(levelFilter, Qt::CaseInsensitive)) {
shouldShow = false;
}
}
// 正则过滤
if (shouldShow && !regexPattern.isEmpty()) {
if (!regex.match(message).hasMatch()) {
shouldShow = false;
}
}
if (shouldShow) {
if (shouldShowMessage(message, state)) {
// 根据日志级别设置颜色
appendColoredMessage(state.textWidget, message);
}
}
// 清空待处理消息,因为已经全部重新过滤了
state.pendingMessages.clear();
// 自动滚动到底部
if (state.autoScroll) {
scrollToBottom(state.textWidget);
@@ -321,8 +387,12 @@ private:
// 保存日志到文件
void saveLogToFile(int index) {
QMutexLocker globalLocker(&globalMutex);
if (filterStates.find(index) == filterStates.end()) return;
FilterState& state = filterStates[index];
QString fileName = QFileDialog::getSaveFileName(
this,
"保存日志文件",
@@ -335,7 +405,15 @@ private:
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
out.setCodec("UTF-8");
out << filterStates[index].textWidget->toPlainText();
// 复制当前显示的内容以避免在写入时内容发生变化
QString content;
{
QMutexLocker stateLocker(&state.mutex);
content = state.textWidget->toPlainText();
}
out << content;
file.close();
QMessageBox::information(this, "成功", "日志已保存到: " + fileName);
} else {
@@ -346,55 +424,72 @@ private:
// 清空日志
void clearLog(int index) {
QMutexLocker globalLocker(&globalMutex);
if (filterStates.find(index) == filterStates.end()) return;
auto reply = QMessageBox::question(this, "确认", "确定要清空当前日志吗?",
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
filterStates[index].allMessages.clear();
filterStates[index].textWidget->clear();
FilterState& state = filterStates[index];
QMutexLocker stateLocker(&state.mutex);
state.allMessages.clear();
state.pendingMessages.clear();
state.textWidget->clear();
}
}
public slots:
void recvStdLogMsg(QString logMsg) {
QString text = getCurrentDate() + " " + getCurrentTime() + " " + logMsg;
// 添加到标准控制台 (索引0)
if (filterStates.find(0) != filterStates.end()) {
filterStates[0].allMessages.append(text);
// 如果当前显示的是标准控制台,应用过滤器显示
if (widgets->currentIndex() == 0) {
applyFilters(0);
}
} else {
// 兜底:直接添加到文本框
stdConsoleOutput.appendPlainText(text);
if (filterStates.size() > 0 && filterStates[0].autoScroll) {
scrollToBottom(&stdConsoleOutput);
}
}
addMessageSafe(0, text); // 使用线程安全的方法
}
void recvQtLogMsg(QString logMsg) {
QString text = getCurrentDate() + " " + getCurrentTime() + " " + logMsg;
addMessageSafe(1, text); // 使用线程安全的方法
}
private slots:
void processPendingMessages() {
QMutexLocker globalLocker(&globalMutex);
// 添加到Qt日志 (索引1)
if (filterStates.find(1) != filterStates.end()) {
filterStates[1].allMessages.append(text);
bool hasUpdates = false;
int currentIndex = widgets->currentIndex();
for (auto& pair : filterStates) {
int index = pair.first;
FilterState& state = pair.second;
// 如果当前显示的是Qt日志,应用过滤器显示
if (widgets->currentIndex() == 1) {
applyFilters(1);
}
} else {
// 兜底:直接添加到文本框
qtConsoleOutput.appendPlainText(text);
if (filterStates.size() > 1 && filterStates[1].autoScroll) {
scrollToBottom(&qtConsoleOutput);
QMutexLocker stateLocker(&state.mutex);
if (!state.pendingMessages.isEmpty()) {
hasUpdates = true;
// 只更新当前显示的页面,提升性能
if (index == currentIndex) {
// 增量添加消息而不是重新过滤所有消息
for (const QString& message : state.pendingMessages) {
if (shouldShowMessage(message, state)) {
appendColoredMessage(state.textWidget, message);
}
}
// 自动滚动到底部
if (state.autoScroll) {
scrollToBottom(state.textWidget);
}
}
state.pendingMessages.clear();
}
}
// 如果没有待处理消息,停止定时器
if (!hasUpdates) {
batchUpdateTimer->stop();
}
}
};
#pragma once
+2 -1
View File
@@ -64,9 +64,10 @@ public:
initConfig();
}
~appCore(){
_backEnd.releaseCore();
auto& config = appConfig::getInstance();
if(config.dataBase) delete config.dataBase;
//backend.releaseCore();
}
void initConfig() {
auto& config = appConfig::getInstance();