From 65948e2eee4a2d08eff46bed68560343461df822 Mon Sep 17 00:00:00 2001 From: liusiyang Date: Tue, 22 Sep 2026 17:02:41 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BF=AE=E6=94=B9=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=B4=A9=E6=BA=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AIEngineModule/include/AIModel_Impl.h | 3 +- AIEngineModule/src/AIModel_Impl.cpp | 3 +- AlgorithmModule/include/DetLog.h | 21 +++++++++- AlgorithmModule/include/ImageResultJudge.h | 2 + AlgorithmModule/src/CameraCheckAnalysisy.cpp | 40 ++++++++++++++------ AlgorithmModule/src/CheckUtil.cpp | 10 +++-- AlgorithmModule/src/ImageResultJudge.cpp | 25 ++++++++++-- ConfigModule/src/ConfigManager.cpp | 2 +- example/Read_Image.cpp | 32 ++++++++-------- 9 files changed, 101 insertions(+), 37 deletions(-) diff --git a/AIEngineModule/include/AIModel_Impl.h b/AIEngineModule/include/AIModel_Impl.h index 03e38d8..877abb2 100644 --- a/AIEngineModule/include/AIModel_Impl.h +++ b/AIEngineModule/include/AIModel_Impl.h @@ -103,7 +103,8 @@ public: } if (cpu_floatData != NULL) { - delete cpu_floatData; + // 与 LoadEngine 中的 new float[datalength] 配对,必须用 delete[] + delete[] cpu_floatData; cpu_floatData = NULL; } } diff --git a/AIEngineModule/src/AIModel_Impl.cpp b/AIEngineModule/src/AIModel_Impl.cpp index 4c07740..faeb525 100644 --- a/AIEngineModule/src/AIModel_Impl.cpp +++ b/AIEngineModule/src/AIModel_Impl.cpp @@ -337,7 +337,8 @@ int AIModel_Impl::LoadEngine(int ngpuIdx) { if (steamNodeconfig->cpu_floatData) { - delete steamNodeconfig->cpu_floatData; + // 与下面 new float[datalength] 配对,必须用 delete[] + delete[] steamNodeconfig->cpu_floatData; steamNodeconfig->cpu_floatData = NULL; } diff --git a/AlgorithmModule/include/DetLog.h b/AlgorithmModule/include/DetLog.h index dacd356..4d2dacf 100644 --- a/AlgorithmModule/include/DetLog.h +++ b/AlgorithmModule/include/DetLog.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "ImgCheckConfig.h" #include "CheckErrorCodeDefine.hpp" using namespace std; @@ -61,6 +62,9 @@ struct DetLog std::vector logList; bool bPrintStr; // 是否打印日志 int addLogLevel; + // 保护 logList:同一个 DetLog(如图片结果的日志)会被实例主线程(Run/CheckRun) + // 与任务线程(AI 推理/分类) 并发写入,无锁 push_back 会造成 vector 堆破坏。 + std::mutex mtx_log; DetLog() { @@ -68,11 +72,19 @@ struct DetLog } void Init() { + std::lock_guard lock(mtx_log); logList.clear(); bPrintStr = false; addLogLevel = DET_LOG_LEVEL_3; } + // 线程安全地获取日志快照 + std::vector GetLogs() + { + std::lock_guard lock(mtx_log); + return logList; + } + template void AddCheckstr(PrintLevel_ step, std::string stepStr, const std::string &format, Args... args) { @@ -105,6 +117,7 @@ struct DetLog printf("%s\n", str.c_str()); } + std::lock_guard lock(mtx_log); logList.push_back(str); } template @@ -141,15 +154,19 @@ struct DetLog if (LogLevel <= addLogLevel) { + std::lock_guard lock(mtx_log); logList.push_back(str); } } void printLog(std::string str) { printf("===========================%s==============================\n", str.c_str()); - for (auto strl : logList) { - printf("%s\n", strl.c_str()); + std::lock_guard lock(mtx_log); + for (auto strl : logList) + { + printf("%s\n", strl.c_str()); + } } printf("==========================================================\n"); } diff --git a/AlgorithmModule/include/ImageResultJudge.h b/AlgorithmModule/include/ImageResultJudge.h index b06697c..649d149 100644 --- a/AlgorithmModule/include/ImageResultJudge.h +++ b/AlgorithmModule/include/ImageResultJudge.h @@ -203,6 +203,8 @@ private: std::condition_variable m_task_cv_; std::shared_ptr ptr_thread_Draw; std::condition_variable m_drawComplate_cv_; + // 正在执行中的绘制任务数(受 m_task_mutex_ 保护),用于 WaiteDrawComplate 精确等待 + int m_nDrawProcessingNum = 0; }; #endif \ No newline at end of file diff --git a/AlgorithmModule/src/CameraCheckAnalysisy.cpp b/AlgorithmModule/src/CameraCheckAnalysisy.cpp index d261fac..693ddef 100644 --- a/AlgorithmModule/src/CameraCheckAnalysisy.cpp +++ b/AlgorithmModule/src/CameraCheckAnalysisy.cpp @@ -790,7 +790,6 @@ int CameraCheckAnalysisy::CheckImgRun() if (m_pCheck_Result->getImgPushComplate()) { curcheckStep = Check_Step_Complete; // 进入到预图片检测阶段 - m_pCheck_Result->SetCheckStep(curcheckStep); } else { @@ -807,7 +806,12 @@ int CameraCheckAnalysisy::CheckImgRun() m_pdetlog->AddCheckstr(PrintLevel_0, "CheckImgRun", "========came %s Check ALL end time %ld ms %s", m_pCheck_Result->cameraBaseResult->strCameraName.c_str(), tend - m_pCheck_Result->time_start, strTimg.c_str()); InsertCameraLog(); + // 结果与日志(det_LogList)全部写完后,才置为 Check_Step_Complete, + // 通知 Det_Product 结果可以交付调用方;并且整个收尾过程保持在 + // mtx_WaiteImg 锁内,与 StartCheck() 对 m_pCheck_Result 的赋值互斥, + // 避免同一 shared_ptr 被并发 reset/赋值(会造成控制块双重释放)。 std::lock_guard lock(mtx_WaiteImg); + m_pCheck_Result->SetCheckStep(Check_Step_Complete); m_bHaveImgeDet = false; m_pCheck_Result.reset(); @@ -851,8 +855,12 @@ int CameraCheckAnalysisy::InsertCameraLog() } // 1、把图片的相关日志 写到 返回 日志中。 - m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), - pImageResult->detlog->logList.begin(), pImageResult->detlog->logList.end()); + // 注意:DetLog 可能仍被实例线程写入,使用 GetLogs() 做加锁快照,避免并发遍历。 + { + std::vector imgLogs = pImageResult->detlog->GetLogs(); + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + imgLogs.begin(), imgLogs.end()); + } std::string str = ""; char buffer[256]; // 2、把缺陷信息 写的 返回日志中。 @@ -883,8 +891,9 @@ int CameraCheckAnalysisy::InsertCameraLog() if (QX_info->result == QX_RESULT_TYPE_NG) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), - pQxLog->logList.begin(), pQxLog->logList.end()); + qxLogs.begin(), qxLogs.end()); } } @@ -900,8 +909,9 @@ int CameraCheckAnalysisy::InsertCameraLog() if (QX_info->result == QX_RESULT_TYPE_YS) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), - pQxLog->logList.begin(), pQxLog->logList.end()); + qxLogs.begin(), qxLogs.end()); } } @@ -917,8 +927,9 @@ int CameraCheckAnalysisy::InsertCameraLog() if (QX_info->result == QX_RESULT_TYPE_OK) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), - pQxLog->logList.begin(), pQxLog->logList.end()); + qxLogs.begin(), qxLogs.end()); } } @@ -934,8 +945,9 @@ int CameraCheckAnalysisy::InsertCameraLog() if (QX_info->result == QX_RESULT_TYPE_NoJduge) { std::shared_ptr pQxLog = pDetResult->pQx_ErrorList->at(qxidx).detlog; + std::vector qxLogs = pQxLog->GetLogs(); m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), - pQxLog->logList.begin(), pQxLog->logList.end()); + qxLogs.begin(), qxLogs.end()); } } } @@ -947,8 +959,11 @@ int CameraCheckAnalysisy::InsertCameraLog() } // 3、把相机的日志 写到 返回日志中。 - m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), - m_pCheck_Result->detlog->logList.begin(), m_pCheck_Result->detlog->logList.end()); + { + std::vector camLogs = m_pCheck_Result->detlog->GetLogs(); + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + camLogs.begin(), camLogs.end()); + } { sprintf(buffer, " =====================Product Log ============================="); @@ -956,8 +971,11 @@ int CameraCheckAnalysisy::InsertCameraLog() m_CheckResult_shareP->det_LogList.push_back(str); } // 4、把产品相关日志 写到 返回日志中。 - m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), - m_pCheck_Result->productBaseResult->detlog->logList.begin(), m_pCheck_Result->productBaseResult->detlog->logList.end()); + { + std::vector productLogs = m_pCheck_Result->productBaseResult->detlog->GetLogs(); + m_CheckResult_shareP->det_LogList.insert(m_CheckResult_shareP->det_LogList.end(), + productLogs.begin(), productLogs.end()); + } } return 0; } diff --git a/AlgorithmModule/src/CheckUtil.cpp b/AlgorithmModule/src/CheckUtil.cpp index c0f50ef..b85f9aa 100644 --- a/AlgorithmModule/src/CheckUtil.cpp +++ b/AlgorithmModule/src/CheckUtil.cpp @@ -67,8 +67,10 @@ std::string CheckUtil::getCurrentDate() // 将 tv_sec 转换为 time_t 类型,代表自1970年1月1日起的秒数 time_t raw_time = tv.tv_sec; - // 使用 localtime 将 time_t 转换为 tm 结构体 - struct tm *time_info = localtime(&raw_time); + // 使用 localtime_r 转换为 tm 结构体。 + // 注意:localtime() 返回共享的静态缓冲区,多线程并发调用会互相覆盖(tm 内容串数据)。 + struct tm time_buf; + struct tm *time_info = localtime_r(&raw_time, &time_buf); // 使用字符串流格式化为 "YYYY-MM-DD" std::ostringstream oss; @@ -84,7 +86,9 @@ std::string CheckUtil::getCurTimeHMS() gettimeofday(&tv, NULL); // 获取当前时间 time_t raw_time = tv.tv_sec; - struct tm *time_info = localtime(&raw_time); + // 使用 localtime_r(线程安全);localtime() 的静态缓冲会被其它线程并发覆盖 + struct tm time_buf; + struct tm *time_info = localtime_r(&raw_time, &time_buf); int millisec = tv.tv_usec / 1000; // 微秒转毫秒 diff --git a/AlgorithmModule/src/ImageResultJudge.cpp b/AlgorithmModule/src/ImageResultJudge.cpp index e951f26..5d5b43b 100644 --- a/AlgorithmModule/src/ImageResultJudge.cpp +++ b/AlgorithmModule/src/ImageResultJudge.cpp @@ -1109,11 +1109,27 @@ void ImageResultJudge::ThreadDraw() while (!m_bExit) { std::this_thread::sleep_for(std::chrono::milliseconds(0)); - // 等待是否有任务 - std::shared_ptr draw = GetTask(); + + std::shared_ptr draw; + // 取任务与 计数+1 必须在同一把锁内完成, + // 否则 WaiteDrawComplate 可能在任务已出队但尚未计数的间隙提前返回。 + { + std::unique_lock lock(m_task_mutex_); + m_task_cv_.wait(lock, [this]() + { return !m_DrawInfoList.empty(); }); + + draw = std::move(m_DrawInfoList.front()); + m_DrawInfoList.pop(); + m_nDrawProcessingNum++; + } // 把任务发送给对应的任务处理函数进行处理 DrawResultTask(draw); + + { + std::lock_guard lock(m_task_mutex_); + m_nDrawProcessingNum--; + } m_drawComplate_cv_.notify_all(); } } @@ -1214,10 +1230,13 @@ int ImageResultJudge::DrawResultTask(std::shared_ptr int ImageResultJudge::WaiteDrawComplate() { + // 等待 所有绘制任务真正执行完成。 + // 旧实现只等待队列为空,而任务在取出时即已出队,绘制仍在后台线程进行, + // 调用方(结果存图/拷贝)可能与绘制线程并发读写同一张图片。 { std::unique_lock lock(m_task_mutex_); m_drawComplate_cv_.wait(lock, [this]() - { return m_DrawInfoList.empty(); }); + { return m_DrawInfoList.empty() && m_nDrawProcessingNum == 0; }); } return 0; } diff --git a/ConfigModule/src/ConfigManager.cpp b/ConfigModule/src/ConfigManager.cpp index f28263d..8ea2c4e 100644 --- a/ConfigModule/src/ConfigManager.cpp +++ b/ConfigModule/src/ConfigManager.cpp @@ -161,7 +161,7 @@ int ConfigManager::UpdateConfig() ReadFlawCodeConfig(defect_list_file); bool bFileName = false; // std::regex pattern(R"(param_[0-9]\.json)"); - std::regex pattern(R"(param_(\d+|left|right)\.json)"); + std::regex pattern(R"(param_.*\.json)"); if (!fs::exists(m_strConfigRootPath)) { std::cerr << "目录不存在: " << m_strConfigRootPath << std::endl; diff --git a/example/Read_Image.cpp b/example/Read_Image.cpp index 39b887e..b4d5a4f 100644 --- a/example/Read_Image.cpp +++ b/example/Read_Image.cpp @@ -185,12 +185,12 @@ std::string Extract_ALL::Extract_Product_Name(std::string strPath, int userflag) // std::cout << strPath << std::endl; fs::path p = fs::path(strPath); - fs::path lastDir = p.parent_path().filename(); + fs::path lastDir = p.parent_path().parent_path().filename(); std::string name = lastDir.string(); - if (name.length()<7) + if (name.empty()) { - lastDir = p.parent_path().parent_path().filename(); + lastDir = p.parent_path().filename(); name = lastDir.string(); } @@ -212,24 +212,26 @@ std::string Extract_ALL::Extract_Channel_Name(std::string strPath, int userflag) } int Extract_ALL::Read_Image_List(std::string strPath, std::string strproduct) { - std::string strSearchImgPath = strPath + "/*.bmp"; - Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); - - // strSearchImgPath = strPath + "/*.png"; - // Read_Camera_Product_Image(strSearchImgPath, 1); + std::vector vecExt = {".bmp", ".png", ".jpg", ".jpeg", ".tif", ".tiff"}; + for (size_t i = 0; i < vecExt.size(); i++) + { + std::string strSearchImgPath = strPath + "/*" + vecExt[i]; + Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); + } return 0; } int Extract_ALL::Read_Image_List(std::string strPath_left, std::string strPath_right, std::string strproduct) { - std::string strSearchImgPath = strPath_left + "/*.bmp"; - Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); - strSearchImgPath = strPath_right + "/*.bmp"; - Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); - - // strSearchImgPath = strPath + "/*.png"; - // Read_Camera_Product_Image(strSearchImgPath, 1); + std::vector vecExt = {".bmp", ".png", ".jpg", ".jpeg", ".tif", ".tiff"}; + for (size_t i = 0; i < vecExt.size(); i++) + { + std::string strSearchImgPath = strPath_left + "/*" + vecExt[i]; + Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); + strSearchImgPath = strPath_right + "/*" + vecExt[i]; + Read_Camera_Product_Image(strSearchImgPath, 0, strproduct); + } return 0; }