#include "CompareItemThread.h" #include "ThreadManager.h" #include "CalculateDBThread.h" #include "NoiseDetectThread.h" #include "CompareDoubleThread.h" #include "ThreadPool.h" #include "spdlog.h" CompareItemThread::CompareItemThread(CalculateThreadInfo_t& threadInfo) : BaseCalculateThread(threadInfo) { } CompareItemThread::~CompareItemThread() { } /* 线程功能函数 */ void CompareItemThread::task() { m_logBase = fmt::format("对比项: {}", m_threadInfo.compareItemInfo.strName.toStdString()); SPDLOG_LOGGER_INFO(m_logger, "----------------------------------------------------------------"); SPDLOG_LOGGER_INFO(m_logger, "{} 线程开始运行, 对比通道: ", m_logBase); for(const auto& road : m_threadInfo.compareItemInfo.mapRoad) { SPDLOG_LOGGER_INFO(m_logger, " 通道名称: {}, 通道编号: {}, 声卡通道: {}:{}", road.strCompareRoadName.toStdString(), road.nCompareRoadNum, road.scRoadInfo.strSoundCardName.toStdString(), road.scRoadInfo.roadInfo.nRoadNum); } SPDLOG_LOGGER_INFO(m_logger, "----------------------------------------------------------------"); /* 测试录音通道用 */ // for(const auto& road : m_threadInfo.compareItemInfo.mapRoad) // { // ThreadMan.createRecordThread(road.scRoadInfo, m_threadInfo.compareItemInfo.nID); // } // while(true) // { // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // } /* 初始化数据 */ if(!initData()) { SPDLOG_LOGGER_ERROR(m_logger, "{} 初始化数据失败", m_logBase); return; } while (m_isRunning) { /* 睡眠100ms */ std::this_thread::sleep_for(std::chrono::milliseconds(100)); /* ------------------------------------------------------------------------------------- * 更新对比项信息 * ------------------------------------------------------------------------------------- */ if(updateThreadInfoInternal()) { SPDLOG_LOGGER_INFO(m_logger, "{} 暂停对比检测,更新对比项信息"); m_threadInfo.compareItemInfo = m_threadInfoNew.compareItemInfo; initData(); SPDLOG_LOGGER_INFO(m_logger, "{} 更新对比项信息完成,继续检测对比"); } /* ------------------------------------------------------------------------------------- * 更新数据 * ------------------------------------------------------------------------------------- */ if(!updateResultData()) { continue; } /* ------------------------------------------------------------------------------------- * 处理数据,将报警信息给写报警数据的线程 * ------------------------------------------------------------------------------------- */ processAlarmData(); /* ------------------------------------------------------------------------------------- * 将音量包数据发送到MQTT中 * ------------------------------------------------------------------------------------- */ sendResultData(); } /* 清理数据 */ clearData(); SPDLOG_LOGGER_INFO(m_logger, "{} 线程结束运行", m_logBase); } /* 初始化数据 */ bool CompareItemThread::initData() { /* 创建录音通道线程 */ for(const auto& road : m_threadInfo.compareItemInfo.mapRoad) { ThreadMan.createRecordThread(road.scRoadInfo, m_threadInfo.compareItemInfo.nID); } /* 创建计算音量报警信息的线程指针 */ destroyCalculateDBThreads(); // 清理之前的线程 createCalculateDBThreads(); /* 获取计算噪音的线程 */ removeNoiseDetectThreads(); // 清理之前的噪音检测线程 getNoiseDetectThreads(); /* 创建两个对比线程,主通道是第一个通道,其他都需要和主通道进行对比 */ destroyCompareThreads(); if(!createCompareThreads()) { return false; } /* 初始化存储结果的数据结构 */ m_compareResult = CompareResult_t(); m_compareResult.compareItemID = m_threadInfo.compareItemInfo.nID; m_compareResult.compareItemName = m_threadInfo.compareItemInfo.strName.toStdString(); m_compareResult.dateTime = QDateTime::currentDateTime(); m_compareResult.isClientAlarm = false; // 默认不报警 m_compareResult.vecRoadVolumes.clear(); // 清空之前的数据 for(const auto& road : m_threadInfo.compareItemInfo.mapRoad) { OneRoadVolume_t oneRoadVolume; oneRoadVolume.roadInfo = road; // 设置通道信息 oneRoadVolume.dateTime = QDateTime::currentDateTime(); // 初始化时间 m_compareResult.vecRoadVolumes.push_back(oneRoadVolume); } int roadCount = m_threadInfo.compareItemInfo.mapRoad.size(); m_vecCDBUpdated.clear(); m_vecCDBUpdated.reserve(roadCount); for(int i = 0; i < m_threadInfo.compareItemInfo.mapRoad.size(); ++i) { m_vecCDBUpdated.push_back(false); // 初始化为未更新 } /* 初始化报警信息 */ m_vecAlarmSilence.clear(); m_vecAlarmOverload.clear(); m_vecAlarmPhase.clear(); m_vecAlarmSilence.reserve(roadCount); m_vecAlarmOverload.reserve(roadCount); m_vecAlarmPhase.reserve(roadCount); m_vecAlarmSilenceLast.clear(); m_vecAlarmOverloadLast.clear(); m_vecAlarmPhaseLast.clear(); m_vecAlarmSilenceLast.reserve(roadCount); m_vecAlarmOverloadLast.reserve(roadCount); m_vecAlarmPhaseLast.reserve(roadCount); return true; } /* 清理数据 */ void CompareItemThread::clearData() { /* 停止所有的比对线程 */ for(auto& thread : m_vecCompareDoubleThreads) { if(thread != nullptr) { thread->stopThreadBlock(); delete thread; thread = nullptr; } } m_vecCompareDoubleThreads.clear(); /* 移除使用到的录音通道 */ for(auto& it : m_threadInfo.compareItemInfo.mapRoad) { SoundCardRoadInfo_t roadInfo = it.scRoadInfo; if(!ThreadMan.removeRecordThread(roadInfo, m_threadInfo.compareItemInfo.nID)) { SPDLOG_LOGGER_ERROR(m_logger, "{} 移除录音通道 {}:{} 失败", m_logBase, roadInfo.strSoundCardName.toStdString(), roadInfo.roadInfo.nRoadNum); } } } /* 创建两个对比线程,主通道是第一个通道,其他都需要和主通道进行对比 */ bool CompareItemThread::createCompareThreads() { auto it = m_threadInfo.compareItemInfo.mapRoad.begin(); auto mainRoad = it.value(); // 主通道信息 uint64_t size = m_threadInfo.compareItemInfo.mapRoad.size(); for(uint64_t i = 1; i < size; ++i) { it++; CalculateThreadInfo_t compareThreadInfo; compareThreadInfo.compareItemInfo = m_threadInfo.compareItemInfo; compareThreadInfo.compareItemInfo.mapRoad.clear(); // 清空通道信息 compareThreadInfo.compareItemInfo.mapRoad.insert(mainRoad.nCompareRoadNum, mainRoad); // 添加主通道 compareThreadInfo.compareItemInfo.mapRoad.insert(it.key(), it.value()); // 添加当前通道 compareThreadInfo.threadState = EThreadState::State_Inited; CompareDoubleThread* pThread = new CompareDoubleThread(compareThreadInfo); if(pThread == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 创建对比线程 {} - {} 失败", m_logBase, mainRoad.strCompareRoadName.toStdString(), it.value().strCompareRoadName.toStdString()); return false; } m_vecCompareDoubleThreads.push_back(pThread); /* 开始运行 */ CPPTP.add_task(&CompareDoubleThread::threadTask, pThread); } return true; } /* 销毁两两对比线程 */ void CompareItemThread::destroyCompareThreads() { if(m_vecCompareDoubleThreads.size() == 0) { return; // 没有对比线程 } SPDLOG_LOGGER_INFO(m_logger, "{} 销毁对比线程", m_logBase); for(auto& thread : m_vecCompareDoubleThreads) { if(thread != nullptr) { thread->stopThreadBlock(); // 停止线程 delete thread; // 删除线程 thread = nullptr; // 设置为nullptr } } m_vecCompareDoubleThreads.clear(); m_vecCDBUpdated.clear(); // 清空更新标志位 SPDLOG_LOGGER_INFO(m_logger, "{} 对比线程销毁完成", m_logBase); } /* 创建计算音量报警的线程 */ bool CompareItemThread::createCalculateDBThreads() { for(const auto& road : m_threadInfo.compareItemInfo.mapRoad) { CalculateThreadInfo_t threadInfo; threadInfo.compareItemInfo.mapRoad.clear(); // 清空通道信息 threadInfo.compareItemInfo.mapRoad.insert(road.nCompareRoadNum, road); // 添加当前通道 threadInfo.threadState = EThreadState::State_Inited; // 初始化线程状态 threadInfo.threadType = EThreadType::Type_CalculateDB; CalculateDBThread* pThread = new CalculateDBThread(threadInfo); if(pThread == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 创建音量计算线程失败", m_logBase); // return false; // 获取线程失败 } CPPTP.add_task(&CalculateDBThread::threadTask, pThread); m_vecCalculateDBThreads.push_back(pThread); } return true; } /* 销毁音量计算的线程 */ void CompareItemThread::destroyCalculateDBThreads() { if(m_vecCalculateDBThreads.size() == 0) { return; // 没有音量计算线程 } SPDLOG_LOGGER_INFO(m_logger, "{} 销毁音量计算线程", m_logBase); for(auto& thread : m_vecCalculateDBThreads) { if(thread != nullptr) { thread->stopThreadBlock(); // 停止线程 delete thread; // 删除线程 thread = nullptr; // 设置为nullptr } } m_vecCalculateDBThreads.clear(); m_vecCDBUpdated.clear(); // 清空更新标志位 SPDLOG_LOGGER_INFO(m_logger, "{} 音量计算线程销毁完成", m_logBase); } /* 获取噪音检测的线程 */ bool CompareItemThread::getNoiseDetectThreads() { for(const auto& road : m_threadInfo.compareItemInfo.mapRoad) { NoiseDetectThread* pThread = ThreadMan.getNoiseDetectThread(road.scRoadInfo, m_threadInfo.compareItemInfo.nID); if(pThread == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取噪音检测线程失败", m_logBase); return false; // 获取线程失败 } m_vecNoiseDetectThreads.push_back(pThread); } return true; } /* 移除噪音检测的线程 */ void CompareItemThread::removeNoiseDetectThreads() { if(m_vecNoiseDetectThreads.size() == 0) { return; // 没有噪音检测线程 } SPDLOG_LOGGER_INFO(m_logger, "{} 移除噪音检测线程", m_logBase); for(auto& thread : m_vecNoiseDetectThreads) { if(thread != nullptr) { ThreadMan.removeNoiseDetectThread(thread->getRoadInfo(), m_threadInfo.compareItemInfo.nID); } } m_vecNoiseDetectThreads.clear(); SPDLOG_LOGGER_INFO(m_logger, "{} 噪音检测线程移除完成", m_logBase); } /** * @brief 更新数据 * 更新数据逻辑: * 1、先从音量计算线程获取最新的音量包信息,如果没有全部更新,则等待下次获取,不进行后面的操作 * 2、获取噪音检测线程的噪音信息和获取一致性信息的线程的结果无需关系是否是最新的 * */ bool CompareItemThread::updateResultData() { const int size = m_threadInfo.compareItemInfo.mapRoad.size(); /* ------------------------------------------------------------------------------------- * 先从音量计算数据中获取音量包信息和报警信息(静音、过载、反相) * ------------------------------------------------------------------------------------- */ for(int i = 0; i < size; ++i) { if(m_vecCDBUpdated[i] == true) { continue; // 已经更新过了 } CalculateDBThread* pThread = m_vecCalculateDBThreads[i]; if(pThread == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取音量计算线程失败", m_logBase); continue; // 跳过这个线程 } /* 获取最新的音量数据 */ if(pThread->getlastVolumeInfo(m_compareResult.vecRoadVolumes[i])) { m_vecCDBUpdated[i] = true; // 标记为已更新 } /* 更新报警信息 */ m_vecAlarmSilence[i] = pThread->getAlarm(EAlarmType::EAT_Silent); m_vecAlarmOverload[i] = pThread->getAlarm(EAlarmType::EAT_Overload); m_vecAlarmPhase[i] = pThread->getAlarm(EAlarmType::EAT_Reversed); } /* 判断是否全部更新,如果没有则返回,等待下次再次获取 */ for(int i = 0; i < size; ++i) { if(m_vecCDBUpdated[i] == false) { // SPDLOG_LOGGER_DEBUG(m_logger, "{} 音量计算线程数据未全部更新,等待下次获取", m_logBase); return false; } } /* ------------------------------------------------------------------------------------- * 获取噪音计算的结果 * ------------------------------------------------------------------------------------- */ for(int i = 0; i < size; ++i) { NoiseDetectThread* pThread = m_vecNoiseDetectThreads[i]; if(pThread == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取噪音检测线程失败", m_logBase); continue; // 跳过这个线程 } /* 获取最新的噪音数据,噪音报警那个标志位貌似没用到 */ m_compareResult.vecRoadVolumes[i].isNoise = pThread->isNoise(); } /* ------------------------------------------------------------------------------------- * 从对比项中获取核对过后的一致性结果 * ------------------------------------------------------------------------------------- */ for(int i = 1; i < size; ++i) { CompareDoubleThread* pThread = m_vecCompareDoubleThreads[i-1]; if(pThread == nullptr) { SPDLOG_LOGGER_ERROR(m_logger, "{} 获取对比线程失败", m_logBase); continue; } /* 获取最新的一致性结果 */ OneRoadVolume_t roadVolume; if(pThread->getlastVolumeInfo(roadVolume)) { m_compareResult.vecRoadVolumes[i].isConsistency = roadVolume.isConsistency; m_compareResult.vecRoadVolumes[i].isNotConsistencyWarning = roadVolume.isNotConsistencyWarning; } } return true; } /* 发送数据 */ void CompareItemThread::sendResultData() { /* 生成json数据 */ /* 发送到mqtt中 */ } /* 处理报警数据,主要是和之前的数据尽情对比,是否是一样的 */ void CompareItemThread::processAlarmData() { m_listAlarm.clear(); /* 处理静音报警数据 */ for(size_t i = 0; i < m_vecAlarmSilence.size(); ++i) { auto& nowAlarm = m_vecAlarmSilence[i]; auto& lastAlarm = m_vecAlarmSilenceLast[i]; if(nowAlarm.isAlarm) { if(lastAlarm == nowAlarm) { continue; // 和上次的报警信息一样,不需要处理 }else { nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID; nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString(); m_listAlarm.push_back(nowAlarm); m_vecAlarmSilenceLast[i] = nowAlarm; } } } /* 处理过载报警数据 */ for(size_t i = 0; i < m_vecAlarmOverload.size(); ++i) { auto& nowAlarm = m_vecAlarmOverload[i]; auto& lastAlarm = m_vecAlarmOverloadLast[i]; if(nowAlarm.isAlarm) { if(lastAlarm == nowAlarm) { continue; // 和上次的报警信息一样,不需要处理 }else { nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID; nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString(); m_listAlarm.push_back(nowAlarm); m_vecAlarmOverloadLast[i] = nowAlarm; } } } /* 处理反相报警数据 */ for(size_t i = 0; i < m_vecAlarmPhase.size(); ++i) { auto& nowAlarm = m_vecAlarmPhase[i]; auto& lastAlarm = m_vecAlarmPhaseLast[i]; if(nowAlarm.isAlarm) { if(lastAlarm == nowAlarm) { continue; // 和上次的报警信息一样,不需要处理 }else { nowAlarm.CompareItemID = m_threadInfo.compareItemInfo.nID; nowAlarm.strCompareItemName = m_threadInfo.compareItemInfo.strName.toStdString(); m_listAlarm.push_back(nowAlarm); m_vecAlarmPhaseLast[i] = nowAlarm; } } } /* 将报警列表写入到处理报警数据的线程中 */ }