From 3756a63a32ac41b52aeb43835d4dd43a4b0dce98 Mon Sep 17 00:00:00 2001 From: yiyi Date: Sun, 4 Jan 2026 23:11:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DVrUtils=E5=8D=95=E4=B8=80?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ParticleSizeApp/ParticleSizeApp.pro | 2 +- .../Presenter/Src/WheelMeasurePresenter.cpp | 11 ++ .../WheelMeasureApp/WheelMeasureApp.pro | 6 - AppUtils/AppCommon/Src/BasePresenter.cpp | 7 ++ VrUtils/Src/VrLog.cpp | 110 ++++++++++++------ 5 files changed, 92 insertions(+), 44 deletions(-) diff --git a/App/ParticleSize/ParticleSizeApp/ParticleSizeApp.pro b/App/ParticleSize/ParticleSizeApp/ParticleSizeApp.pro index 88f3781..54f78c5 100644 --- a/App/ParticleSize/ParticleSizeApp/ParticleSizeApp.pro +++ b/App/ParticleSize/ParticleSizeApp/ParticleSizeApp.pro @@ -148,7 +148,7 @@ win32:CONFIG(release, debug|release): { } else:win32:CONFIG(debug, debug|release): { LIBS += -L$$PWD/../../../AppAlgo/particleSizeMeasure/Windows/x64/Debug -lparticleSizeMeasurement -lbaseAlgorithm - LIBS += -L$$PWD/../../../SDK/OpenCV320/Windows/vc14/Debug -lopencv_world320d + LIBS += -L$$PWD/../../../SDK/OpenCV320/Windows/vc14/Release -lopencv_world320 } else:unix:!macx: { LIBS += -L$$PWD/../../../AppAlgo/particleSizeMeasure/Arm/aarch64 -lparticleSizeMeasurement -lbaseAlgorithm diff --git a/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp b/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp index 3407d2c..c401236 100644 --- a/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp +++ b/App/WheelMeasure/WheelMeasureApp/Presenter/Src/WheelMeasurePresenter.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -24,6 +25,16 @@ WheelMeasurePresenter::WheelMeasurePresenter(QObject* parent) WheelMeasurePresenter::~WheelMeasurePresenter() { + // 清除状态回调,防止后续回调访问已销毁对象 + m_statusUpdate = nullptr; + + // 停止顺序检测 + m_stopSequentialRequested = true; + m_sequentialDetecting = false; + + // 处理待处理的 Qt 事件,确保 QueuedConnection 的回调不会访问已销毁对象 + QCoreApplication::processEvents(); + if (m_config) { delete m_config; m_config = nullptr; diff --git a/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro b/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro index 1974763..a20068c 100644 --- a/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro +++ b/App/WheelMeasure/WheelMeasureApp/WheelMeasureApp.pro @@ -41,9 +41,6 @@ win32:CONFIG(debug, debug|release) { LIBS += -L../../../AppUtils/AppCommon/debug -lAppCommon LIBS += -L../../../Module/ModbusTCPServer/debug -lModbusTCPServer LIBS += -L../../../VrNets/debug -lVrModbus - - # VzNLSDK - LIBS += -L../../../SDK/Device/VzNLSDK/Windows/x64/Debug -lVzKerneld } else:win32:CONFIG(release, debug|release) { LIBS += -L../WheelMeasureConfig/release -lWheelMeasureConfig LIBS += -L../../../VrNets/release -lVrTcpClient @@ -54,9 +51,6 @@ win32:CONFIG(debug, debug|release) { LIBS += -L../../../AppUtils/AppCommon/release -lAppCommon LIBS += -L../../../Module/ModbusTCPServer/release -lModbusTCPServer LIBS += -L../../../VrNets/release -lVrModbus - - # VzNLSDK - LIBS += -L../../../Device/VrEyeDevice/release -lVrEyeDevice }else:unix:!macx { # 注意:静态库链接顺序很重要,被依赖的库必须放在后面 LIBS += -L../WheelMeasureConfig -lWheelMeasureConfig diff --git a/AppUtils/AppCommon/Src/BasePresenter.cpp b/AppUtils/AppCommon/Src/BasePresenter.cpp index 954e994..9b2af23 100644 --- a/AppUtils/AppCommon/Src/BasePresenter.cpp +++ b/AppUtils/AppCommon/Src/BasePresenter.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "PathManager.h" #include "IYModbusTCPServer.h" @@ -22,11 +23,17 @@ BasePresenter::BasePresenter(QObject *parent) BasePresenter::~BasePresenter() { + // 清除状态回调指针,防止后续回调访问 + m_pStatusCallback = nullptr; + // 等待初始化线程完成 if (m_initThread.joinable()) { m_initThread.join(); } + // 处理待处理的 Qt 事件,确保 QueuedConnection 的回调执行时检查到 m_pStatusCallback 为空 + QCoreApplication::processEvents(); + // 停止检测线程 StopAlgoDetectThread(); diff --git a/VrUtils/Src/VrLog.cpp b/VrUtils/Src/VrLog.cpp index 7362958..349bf14 100644 --- a/VrUtils/Src/VrLog.cpp +++ b/VrUtils/Src/VrLog.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -41,10 +43,29 @@ #define LOG_CONFIG_FILE "config.ini" #define LOG_PRINT_FILE "AppLog.log" -static log4cpp::PatternLayout* m_pLayout = nullptr; -static log4cpp::RollingFileAppender* m_prollfileAppender = nullptr; -static bool g_isLogInitialized = false; -static bool g_isTimeEnabled = true; +// 使用函数内静态变量实现真正的全局单例(跨静态库安全) +struct VrLogState { + log4cpp::PatternLayout* pLayout = nullptr; + log4cpp::RollingFileAppender* pRollFileAppender = nullptr; + std::atomic isInitialized{false}; + std::atomic isShutdown{false}; // 标记日志系统是否已关闭(程序退出时) + std::atomic isTimeEnabled{true}; + std::once_flag initFlag; + std::once_flag uninitFlag; +}; + +// 函数内静态变量,确保跨编译单元的唯一性 +static VrLogState& GetLogState() { + static VrLogState state; + return state; +} + +// 兼容旧代码的访问方式 +#define m_pLayout (GetLogState().pLayout) +#define m_prollfileAppender (GetLogState().pRollFileAppender) +#define g_isLogInitialized (GetLogState().isInitialized) +#define g_isLogShutdown (GetLogState().isShutdown) +#define g_isTimeEnabled (GetLogState().isTimeEnabled) #ifdef STM32_UCOSIII @@ -165,14 +186,9 @@ public: // 静态实例,程序启动时自动初始化日志,程序退出时自动清理日志 static VrLogAutoCleaner g_logAutoCleaner; -/// 初始化log -void VrLogUtils::InitLog() +// 实际执行初始化的内部函数 +static void DoInitLog() { - // 防止重复初始化 - if (g_isLogInitialized) { - return; - } - #ifdef _WIN32 // 设置控制台代码页为 UTF-8,解决中文乱码 SetConsoleOutputCP(CP_UTF8); @@ -204,55 +220,70 @@ void VrLogUtils::InitLog() } // create file appender - if (nullptr == m_pLayout) + VrLogState& state = GetLogState(); + if (nullptr == state.pLayout) { - m_pLayout = new log4cpp::PatternLayout; + state.pLayout = new log4cpp::PatternLayout; // 设置布局格式,可以控制是否自动换行 // %d{%Y-%m-%d %H:%M:%S.%l} [%p] %c - %m%n // 其中 %n 表示换行符,如果想要控制换行可以去掉或修改这个 - m_pLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %m"); + state.pLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %m"); } - if (nullptr == m_prollfileAppender) + if (nullptr == state.pRollFileAppender) { - m_prollfileAppender = new log4cpp::RollingFileAppender("AppLogAppender", logPath + PATH_SEP + LOG_PRINT_FILE, + state.pRollFileAppender = new log4cpp::RollingFileAppender("AppLogAppender", logPath + PATH_SEP + LOG_PRINT_FILE, 1024 * 1024, // 单个文件大小1M 10); // 10个文件 - m_prollfileAppender->setLayout(m_pLayout); + state.pRollFileAppender->setLayout(state.pLayout); // add appender to category log4cpp::Category& root = log4cpp::Category::getRoot(); - root.addAppender(m_prollfileAppender); + root.addAppender(state.pRollFileAppender); // set priority root.setPriority(log4cpp::Priority::DEBUG); } } - + g_isLogInitialized = true; } +/// 初始化log +void VrLogUtils::InitLog() +{ + // 如果已经关闭,不再初始化 + if (g_isLogShutdown) { + return; + } + + // 使用 call_once 确保只执行一次初始化(跨静态库安全) + std::call_once(GetLogState().initFlag, DoInitLog); +} + +// 实际执行清理的内部函数 +static void DoUninitLog() +{ + // 先设置标志,防止其他线程继续调用日志 + g_isLogInitialized = false; + g_isLogShutdown = true; // 标记已关闭,防止 EchoLog 重新初始化 + + // 注意:不调用 log4cpp::Category::shutdown() + // 原因:静态对象析构顺序不确定,log4cpp 内部的静态对象可能在 + // VrLogAutoCleaner 之前就已经被析构,此时调用 shutdown() 会崩溃。 + // 程序退出时,操作系统会自动回收所有内存,不需要手动清理。 + + // 只置空指针,不删除对象(对象由 log4cpp 内部管理) + VrLogState& state = GetLogState(); + state.pLayout = nullptr; + state.pRollFileAppender = nullptr; +} + /// 关闭log void VrLogUtils::UninitLog() { - if (!g_isLogInitialized) { - return; - } - - if (m_pLayout) - { - delete m_pLayout; - m_pLayout = nullptr; - } - - if (m_prollfileAppender) - { - delete m_prollfileAppender; - m_prollfileAppender = nullptr; - } - log4cpp::Category::shutdown();//关闭Category; - - g_isLogInitialized = false; + // 使用 call_once 确保只执行一次清理(跨静态库安全) + std::call_once(GetLogState().uninitFlag, DoUninitLog); } @@ -269,6 +300,11 @@ void VrLogUtils::EnableTime(bool bEnable) /// 输出log void VrLogUtils::EchoLog(VrLogLevel eLogLevel, const char* sFilePath, const int nLine, const char* sLogGroup, const char* sFormat, ...) { + // 如果日志系统已关闭(程序退出),直接返回,不要重新初始化 + if (g_isLogShutdown) { + return; + } + // 由于VrLogAutoCleaner会在程序启动时自动初始化,这里只做保险检查 if (!g_isLogInitialized) { InitLog();