From b1818e8fcee8d0f830b637fe49544bdd058cb55e Mon Sep 17 00:00:00 2001 From: RCi <15089880081@163.com> Date: Sun, 21 Sep 2025 18:53:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=90=8E=E7=AB=AF=E6=9E=90?= =?UTF-8?q?=E6=9E=84=E9=80=BB=E8=BE=91=E4=BB=A5=E5=8F=8A=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detProcess.hpp | 216 ------------------ src/Core/back/triggerManager.h | 1 - src/Core/backendInterface.cpp | 12 +- src/Core/detProcess.hpp | 6 +- src/launcher/GUI/front/pages/logPageWidget.h | 195 ++++++++++++---- src/launcher/appCore.hpp | 3 +- 6 files changed, 161 insertions(+), 272 deletions(-) delete mode 100644 enc_temp_folder/133fe44af4994a7ec31e3fea081bbff/detProcess.hpp diff --git a/enc_temp_folder/133fe44af4994a7ec31e3fea081bbff/detProcess.hpp b/enc_temp_folder/133fe44af4994a7ec31e3fea081bbff/detProcess.hpp deleted file mode 100644 index 171c00b..0000000 --- a/enc_temp_folder/133fe44af4994a7ec31e3fea081bbff/detProcess.hpp +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -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 - 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 diff --git a/src/Core/back/triggerManager.h b/src/Core/back/triggerManager.h index f464fbb..ae461bd 100644 --- a/src/Core/back/triggerManager.h +++ b/src/Core/back/triggerManager.h @@ -66,7 +66,6 @@ public: ~triggerManager(){ runFlag = false; this->stop(); - this->terminate(); delete trigger; } triggerManager(detProcess*, qtFuncBridge* bridgeIn, nlohmann::ordered_json& triggerJson); diff --git a/src/Core/backendInterface.cpp b/src/Core/backendInterface.cpp index f756a85..4f874d0 100644 --- a/src/Core/backendInterface.cpp +++ b/src/Core/backendInterface.cpp @@ -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; }; diff --git a/src/Core/detProcess.hpp b/src/Core/detProcess.hpp index ef2ddd6..c6f9a25 100644 --- a/src/Core/detProcess.hpp +++ b/src/Core/detProcess.hpp @@ -18,7 +18,11 @@ public: db(dbIn),bridge(bridgeIn), missionJson(jsonIn){ } - + ~detProcess() { + safeShutdownDelete(_serviceManager._triggerManager); + safeShutdownDelete(_serviceManager._cameraManager); + safeDelete(_serviceManager._handleAiModelManager); + } // 对普通指针的安全删除 template void safeDelete(T*& ptr) { diff --git a/src/launcher/GUI/front/pages/logPageWidget.h b/src/launcher/GUI/front/pages/logPageWidget.h index 48b435c..302c44b 100644 --- a/src/launcher/GUI/front/pages/logPageWidget.h +++ b/src/launcher/GUI/front/pages/logPageWidget.h @@ -24,9 +24,16 @@ #include #include #include +#include +#include +#include //行数上限 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 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 \ No newline at end of file diff --git a/src/launcher/appCore.hpp b/src/launcher/appCore.hpp index df7dd0b..1efdb40 100644 --- a/src/launcher/appCore.hpp +++ b/src/launcher/appCore.hpp @@ -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();