Browse Source

1.增加线程监控功能

kappo96 2 weeks ago
parent
commit
410a1c2671

+ 25 - 1
.vscode/settings.json

@@ -74,6 +74,30 @@
         "codecvt": "cpp",
         "forward_list": "cpp",
         "unordered_set": "cpp",
-        "valarray": "cpp"
+        "valarray": "cpp",
+        "cfenv": "cpp",
+        "charconv": "cpp",
+        "coroutine": "cpp",
+        "csignal": "cpp",
+        "format": "cpp",
+        "future": "cpp",
+        "ios": "cpp",
+        "locale": "cpp",
+        "scoped_allocator": "cpp",
+        "typeindex": "cpp",
+        "xfacet": "cpp",
+        "xhash": "cpp",
+        "xiosbase": "cpp",
+        "xlocale": "cpp",
+        "xlocbuf": "cpp",
+        "xlocinfo": "cpp",
+        "xlocmes": "cpp",
+        "xlocmon": "cpp",
+        "xlocnum": "cpp",
+        "xloctime": "cpp",
+        "xmemory": "cpp",
+        "xtr1common": "cpp",
+        "xtree": "cpp",
+        "xutility": "cpp"
     }
 }

+ 0 - 1
AIManager/PPYOLOE.cpp

@@ -18,7 +18,6 @@ PPYOLOE::~PPYOLOE()
 bool PPYOLOE::initialize(const std::string &model_path)
 {
     static int index_flag = 0;
-    this->index = index_flag++;
 
     model_data = load_model(model_path.c_str(), &model_data_size);
     if (!model_data)

+ 57 - 7
AIManager/RKNNManager.cpp

@@ -3,6 +3,7 @@
 #include "../DataManager/DataManager.h"
 #include "../DataManager/DataPackage.h"
 #include "../LogRecorder/LogOutput.h"
+#include "../ThreadGuardian/ThreadGuardian.h"
 // Image test
 #include "../ImageTest/ImageTest.h"
 #include <stdexcept>
@@ -11,9 +12,21 @@ void RKNNManager::addRknnTask(std::string modelData)
 {
     try
     {
-        m_threads.emplace_back(&RKNNManager::taskThread, this, modelData);
-        m_threads.emplace_back(&RKNNManager::taskThread, this, modelData);
-        m_threads.emplace_back(&RKNNManager::taskThread, this, modelData);
+        m_vThreadSwitch.resize(3);
+        m_threads.clear();
+        m_bThreadSwitch = true;
+
+        m_threads.emplace_back(&RKNNManager::taskThread, this, 0, modelData);
+        int index = m_threads.size() - 1;
+        ThreadGuardian::getInstance().registerAIThread(index, std::bind(&RKNNManager::restartRknnThread, this, 0));
+
+        m_threads.emplace_back(&RKNNManager::taskThread, this, 1, modelData);
+        index = m_threads.size() - 1;
+        ThreadGuardian::getInstance().registerAIThread(index, std::bind(&RKNNManager::restartRknnThread, this, 1));
+
+        m_threads.emplace_back(&RKNNManager::taskThread, this, 2, modelData);
+        index = m_threads.size() - 1;
+        ThreadGuardian::getInstance().registerAIThread(index, std::bind(&RKNNManager::restartRknnThread, this, 2));
     }
     catch (const std::exception &e)
     {
@@ -25,7 +38,41 @@ void RKNNManager::addRknnTask(std::string modelData)
     }
 }
 
-void RKNNManager::taskThread(std::string modelpath)
+void RKNNManager::restartRknnThread(int threadIndex)
+{
+    // 先停止当前线程
+    // if (m_threads[threadIndex].joinable())
+    // {
+    //     m_vThreadSwitch[threadIndex] = false;
+    //     m_threads[threadIndex].join();
+    // }
+
+    if (threadIndex >= 0 && threadIndex < m_threads.size())
+    {
+        // // 1. 检查旧线程是否可合并(仍在运行)
+        // if (m_threads[threadIndex].joinable())
+        // {
+        //     // 2. 选择等待旧线程结束或分离它(二选一)
+        //     m_threads[threadIndex].join(); // 等待旧线程完成
+        //     // 或者
+        //     // m_threads[threadIndex].detach(); // 让旧线程独立运行(有风险!)
+        // }
+
+        // 重新启动线程
+        if (threadIndex >= 0 && threadIndex < m_threads.size())
+        {
+            m_threads[threadIndex] = std::thread(&RKNNManager::taskThread, this, threadIndex, m_modelData);
+        }
+    }
+}
+
+void RKNNManager::updateThreadStatus(int threadIndex)
+{
+    std::string threadName = "rknnThread_" + std::to_string(threadIndex);
+    ThreadGuardian::getInstance().updateThreadHeartbeat(threadName);
+}
+
+void RKNNManager::taskThread(int index, std::string modelpath)
 {
     grpc::ClientContext *context;
     R360::Empty response;
@@ -35,6 +82,10 @@ void RKNNManager::taskThread(std::string modelpath)
     channel_args.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, 100 * 1024 * 1024);    // 设置最大发送消息大小为100MB
     channel_args.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, 100 * 1024 * 1024); // 设置最大接收消息大小为100MB
     channel_args.SetInt(GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE, 4 * 1024 * 1024);
+    channel_args.SetInt(GRPC_ARG_MAX_RECONNECT_BACKOFF_MS, 10000);    // 10秒
+    channel_args.SetInt(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, 1000);     // 1秒
+    channel_args.SetInt(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, 1000); // 1
+    channel_args.SetInt(GRPC_ARG_ENABLE_RETRIES, 1);                  // 启用重试机制
     std::unique_ptr<MessageService::Stub> stub_ = MessageService::NewStub(grpc::CreateCustomChannel(target_str, grpc::InsecureChannelCredentials(), channel_args));
     std::unique_ptr<grpc::ClientWriter<DataList>> writer;
 
@@ -50,8 +101,6 @@ void RKNNManager::taskThread(std::string modelpath)
         LOG_INFO("The model initialize is failed!!!\n");
         return;
     }
-    m_threadSwitch = true;
-    int index = infer.get_index();
     DataPackagePtr dataPackage;
     std::string pipeName = "rknn" + std::to_string(index);
 
@@ -68,10 +117,11 @@ void RKNNManager::taskThread(std::string modelpath)
     // time test
     UsbTest::HighResolutionTimer timer;
 
-    while (m_threadSwitch)
+    while (m_bThreadSwitch)
     {
         try
         {
+            updateThreadStatus(index);
             if (DataManager::getInstance().popData("resized" + std::to_string(index), dataPackage))
             {
                 try

+ 16 - 4
AIManager/RKNNManager.h

@@ -1,4 +1,3 @@
-
 #ifndef RKNNMANAGER_H
 #define RKNNMANAGER_H
 
@@ -27,10 +26,20 @@ public:
     }
 
     void addRknnTask(std::string modelData);
+    
+    // 用于重启特定线程
+    void restartRknnThread(int threadIndex);
+    
+    // 检查线程状态并更新线程心跳
+    void updateThreadStatus(int threadIndex);
 
     void StopProcessData()
     {
-        m_threadSwitch = false;
+        for(int i = 0; i < m_threads.size(); i++)
+        {
+            m_vThreadSwitch[i] = false;
+        }
+
         for (auto &thread : m_threads)
         {
             if (thread.joinable())
@@ -44,7 +53,7 @@ private:
     RKNNManager() = default;
     ~RKNNManager() = default;
 
-    void taskThread(std::string modelData);
+    void taskThread(int index, std::string modelData);
 
     // 建立gRPC通道
     bool setupGrpcChannel(
@@ -56,11 +65,14 @@ private:
 
 private:
     std::vector<std::thread> m_threads;
+    std::vector<std::thread::id> m_threadIds;
+    std::string m_modelData;
 
     std::string m_grpcServerAddress;
 
     // thread switch
-    bool m_threadSwitch{false};
+    std::vector<bool> m_vThreadSwitch;
+    bool m_bThreadSwitch;
 };
 
 #endif // RKNNMANAGER_H

+ 2 - 1
CMakeLists.txt

@@ -46,10 +46,11 @@ set(RGA_COLORTRANSFER ${CMAKE_CURRENT_SOURCE_DIR}/RGAColorTransfer/RgaColorTrans
 set(DATA_CONTROL ${CMAKE_CURRENT_SOURCE_DIR}/DataManager/DataManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DataManager/DataPipe.h)
 set(AI_SOURCE  ${CMAKE_CURRENT_SOURCE_DIR}/AIManager/beforeProcess.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AIManager/postprocess.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AIManager/RKNNManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AIManager/PPYOLOE.cpp)
 set(GRPC_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/GrpcTransfer/ImageService.pb.cc ${CMAKE_CURRENT_SOURCE_DIR}/GrpcTransfer/ImageService.grpc.pb.cc ${CMAKE_CURRENT_SOURCE_DIR}/GrpcTransfer/GrpcTransfer.cpp)
+set(THREAD_GUARDIAN ${CMAKE_CURRENT_SOURCE_DIR}/ThreadGuardian/ThreadGuardian.cpp)
 set(TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/ImageTest/ImageTest.cpp)
 set(LOG_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/LogRecorder/LogOutput.cpp)
 
-add_executable(${TARGET} ${SOURCES} ${UVC_CONTROL} ${MPP_DECODER} ${RGA_COLORTRANSFER} ${AI_SOURCE} ${DATA_CONTROL} ${GRPC_SOURCE} ${TEST_SOURCE} ${LOG_SOURCE})
+add_executable(${TARGET} ${SOURCES} ${UVC_CONTROL} ${MPP_DECODER} ${RGA_COLORTRANSFER} ${AI_SOURCE} ${DATA_CONTROL} ${GRPC_SOURCE} ${TEST_SOURCE} ${LOG_SOURCE} ${THREAD_GUARDIAN})
 
 set_property(GLOBAL PROPERTY JOB_POOLS single_threaded=1)
 set_property(TARGET ${TARGET} PROPERTY JOB_POOL_COMPILE single_threaded)

+ 5 - 0
DataManager/DataManager.h

@@ -63,6 +63,11 @@ private:
 template <typename T>
 void DataManager::addDataPipe(std::string name)
 {
+    // Check if the data pipe already exists
+    if (m_dataPipes.find(name) != m_dataPipes.end())
+    {
+        return;
+    }
     auto dataPipe = std::make_shared<DataPipe<T>>();
     m_dataPipes[name] = dataPipe;
 }

+ 0 - 2
MppDecoder/MppDecoder.cpp

@@ -8,8 +8,6 @@ bool MppDecoder::init()
 {
     MppDecCfg cfg = NULL;
     RK_U32 need_split = 1;
-    static int index = 0;
-    m_index = index++;
     if (m_rgbData == nullptr)
     {
         m_rgbData = new unsigned char[m_width * m_height * 3];

+ 48 - 13
MppDecoder/MppManager.cpp

@@ -1,47 +1,82 @@
 #include "MppManager.h"
 #include "../DataManager/DataManager.h"
 #include "../DataManager/DataPackage.h"
+#include "../ThreadGuardian/ThreadGuardian.h"
 #include "../RGAColorTransfer/RgaColorTransfer.h"
 #include <thread>
 #include "../ImageTest/ImageTest.h"
 // ...existing code...
 
+void MppManager::updateThreadStatus(int threadIndex)
+{
+    std::string threadName = "mppThread_" + std::to_string(threadIndex);
+    ThreadGuardian::getInstance().updateThreadHeartbeat(threadName);
+}
+
 MppManager::~MppManager()
 {
-    for (auto &thread : m_threads)
+
+    for (int i = 0; i < m_threads.size(); i++)
     {
-        m_threadSwitch = false;
-        if (thread.joinable())
+        m_bThreadSwitch = false;
+        if (m_threads[i].joinable())
         {
-            thread.join();
+            m_threads[i].join();
         }
     }
 }
 
 void MppManager::addMppDecode()
 {
-    m_threads.emplace_back(&MppManager::decodeThread, this);
-    m_threads.emplace_back(&MppManager::decodeThread, this);
-    m_threads.emplace_back(&MppManager::decodeThread, this);
+    m_vThreadSwitch.resize(3);
+    m_bThreadSwitch = true;
+    m_threads.emplace_back(&MppManager::decodeThread, this, 0);
+    int index = m_threads.size() - 1;
+    ThreadGuardian::getInstance().registerMppThread(index, std::bind(&MppManager::restartDecodeThread, this, index));
+
+    m_threads.emplace_back(&MppManager::decodeThread, this, 1);
+    index = m_threads.size() - 1;
+    ThreadGuardian::getInstance().registerMppThread(index, std::bind(&MppManager::restartDecodeThread, this, index));
+
+    m_threads.emplace_back(&MppManager::decodeThread, this, 2);
+    index = m_threads.size() - 1;
+    ThreadGuardian::getInstance().registerMppThread(index, std::bind(&MppManager::restartDecodeThread, this, index));
+}
+
+void MppManager::restartDecodeThread(int threadIndex)
+{
+    // 先停止当前线程
+    // if (m_threads[threadIndex].joinable())
+    // {
+    //     m_vThreadSwitch[threadIndex] = false;
+    //     m_threads[threadIndex].join();
+    // }
+
+    // 重新启动线程
+    if (threadIndex >= 0 && threadIndex < m_threads.size())
+    {
+        m_threads[threadIndex] = std::thread(&MppManager::decodeThread, this, threadIndex);
+        std::cout << "MPP线程 " << threadIndex << " 已重新启动" << std::endl;
+    }
 }
 
-void MppManager::decodeThread()
+void MppManager::decodeThread(int index)
 {
     MppDecoder decoder;
     decoder.init();
     RgaColorTransfer colorTransfer;
     unsigned char *rgbData = nullptr;
     int width = 0, height = 0;
-    m_threadSwitch = true;
-    int index = decoder.getDecodeIndex();
     DataManager::getInstance().addDataPipe<DataPackagePtr>("resized" + std::to_string(index));
 
     // test
     UsbTest::HighResolutionTimer timer;
 
-    while (m_threadSwitch)
+    while (m_bThreadSwitch)
     {
         DataPackagePtr dataPackage = nullptr;
+        // update thread status
+        updateThreadStatus(index);
         if (DataManager::getInstance().popData("uvc" + std::to_string(index), dataPackage))
         {
             decoder.decodeJpegToRgb((const char *)dataPackage->pJpegData, dataPackage->nJpegSize, (unsigned char **)&dataPackage->pRGBData, &width, &height);
@@ -50,7 +85,7 @@ void MppManager::decodeThread()
                 std::cerr << "the decode result is different from defined !!" << std::endl;
             }
 
-            // ImageTest::saveImageFromData((unsigned char *)dataPackage->pRGBData, dataPackage->nResizeWidth, dataPackage->nResizeHeight);
+            std::cout << "Decoded frame " << index << std::endl;
 
             // color transfer
             resize_image(dataPackage->pRGBData, width, height, dataPackage->pResizeData, dataPackage->nResizeWidth, dataPackage->nResizeHeight);
@@ -58,7 +93,7 @@ void MppManager::decodeThread()
             // ImageTest::saveImageFromData((unsigned char *)dataPackage->pResizeData, dataPackage->nResizeWidth, dataPackage->nResizeHeight);
 
             std::string logMessage = "Decoded frame " + std::to_string(index) + " degree : " + std::to_string(dataPackage->dDegree) + " " + UsbTest::GlobalResolutionTimer::getInstance().pressStopWatchString();
-            //UsbTest::TimeRecorder::getInstance().recordTime(logMessage);
+            // UsbTest::TimeRecorder::getInstance().recordTime(logMessage);
 
             // push data to the next pipe
             DataManager::getInstance().pushData("resized" + std::to_string(index), dataPackage);

+ 11 - 2
MppDecoder/MppManager.h

@@ -6,6 +6,7 @@
 #include "MppDecoder.h"
 #include <thread>
 #include <vector>
+#include <functional>
 
 class MppManager
 {
@@ -20,18 +21,26 @@ public:
     MppManager &operator=(const MppManager &) = delete;
 
     void addMppDecode();
+    
+    // 用于重启单个线程
+    void restartDecodeThread(int threadIndex);
+    
+    // 检查线程状态并更新线程心跳
+    void updateThreadStatus(int threadIndex);
 
 private:
     MppManager() = default;
     ~MppManager();
 
-    void decodeThread();
+    void decodeThread(int index);
 
 private:
     std::vector<std::thread> m_threads;
+    std::vector<std::thread::id> m_threadIds;
 
     // thread switch
-    bool m_threadSwitch{false};
+    std::vector<bool> m_vThreadSwitch;
+    bool m_bThreadSwitch;
 };
 
 #endif // MPPMANAGER_H

+ 128 - 0
ThreadGuardian/ThreadGuardian.cpp

@@ -0,0 +1,128 @@
+#include "ThreadGuardian.h"
+#include "../MppDecoder/MppManager.h"
+#include "../AIManager/RKNNManager.h"
+#include "../LogRecorder/LogOutput.h"
+#include <iostream>
+
+ThreadGuardian::ThreadGuardian() : m_running(false) {
+    LOG_INFO("ThreadGuardian 初始化");
+}
+
+ThreadGuardian::~ThreadGuardian() {
+    stopMonitoring();
+    LOG_INFO("ThreadGuardian 销毁");
+}
+
+void ThreadGuardian::startMonitoring() {
+    if (!m_running.exchange(true)) {
+        LOG_INFO("启动线程监控");
+        m_monitorThread = std::thread(&ThreadGuardian::monitorThreads, this);
+    }
+}
+
+void ThreadGuardian::stopMonitoring() {
+    if (m_running.exchange(false)) {
+        LOG_INFO("停止线程监控");
+        if (m_monitorThread.joinable()) {
+            m_monitorThread.join();
+        }
+    }
+}
+
+void ThreadGuardian::registerMppThread(int threadIndex, std::function<void(int)> restartFunc) {
+    std::lock_guard<std::mutex> lock(m_threadMapMutex);
+    
+    ThreadInfo info;
+    info.threadIndex = threadIndex;
+    info.name = "mppThread_" + std::to_string(threadIndex);
+    info.isRunning = true;
+    info.lastAliveTime = std::chrono::steady_clock::now();
+    info.restartFunc = restartFunc;
+    
+    m_threads[info.name] = info;
+    LOG_INFO("注册MPP线程: {}", info.name);
+}
+
+void ThreadGuardian::registerAIThread(int threadIndex, std::function<void(int)> restartFunc) {
+    std::lock_guard<std::mutex> lock(m_threadMapMutex);
+    
+    ThreadInfo info;
+    info.threadIndex = threadIndex;
+    info.name = "rknnThread_" + std::to_string(threadIndex);
+    info.isRunning = true;
+    info.lastAliveTime = std::chrono::steady_clock::now();
+    info.restartFunc = restartFunc;
+    
+    m_threads[info.name] = info;
+    LOG_INFO("注册AI线程: {}", info.name);
+}
+
+void ThreadGuardian::updateThreadHeartbeat(std::string threadName) {
+    std::lock_guard<std::mutex> lock(m_threadMapMutex);
+    
+    auto it = m_threads.find(threadName);
+    if (it != m_threads.end()) {
+        it->second.lastAliveTime = std::chrono::steady_clock::now();
+        it->second.isRunning = true;
+    }
+
+}
+
+void ThreadGuardian::unregisterThread(std::string threadName) {
+    std::lock_guard<std::mutex> lock(m_threadMapMutex);
+    
+    auto it = m_threads.find(threadName);
+    if (it != m_threads.end()) {
+        LOG_INFO("注销线程: {}", it->second.name);
+        m_threads.erase(it);
+    }
+}
+
+void ThreadGuardian::monitorThreads() {
+    LOG_INFO("线程监控已启动");
+    
+    while (m_running) {
+        // 睡眠一段时间后检查线程状态
+        std::this_thread::sleep_for(m_checkInterval);
+        
+        std::lock_guard<std::mutex> lock(m_threadMapMutex);
+        auto now = std::chrono::steady_clock::now();
+        
+        for (auto& pair : m_threads) {
+            auto& info = pair.second;
+            auto timeSinceLastHeartbeat = std::chrono::duration_cast<std::chrono::seconds>(now - info.lastAliveTime);
+                
+            // 如果线程心跳超时,认为线程异常
+            if (timeSinceLastHeartbeat > m_threadTimeout) {
+                LOG_WARN("检测到线程 {} 可能已退出,尝试恢复", info.name);
+                info.isRunning = false;
+                
+                // 调用重启函数
+                restartThread(info);
+                
+                // 更新心跳时间,避免重复恢复
+                info.lastAliveTime = now;
+            }
+        }
+    }
+    
+    LOG_INFO("线程监控已停止");
+}
+
+void ThreadGuardian::restartThread(const ThreadInfo& threadInfo) {
+    try {
+        LOG_INFO("正在恢复线程: {}", threadInfo.name);
+        
+        // 执行重启函数
+        if (threadInfo.restartFunc) {
+            threadInfo.restartFunc(threadInfo.threadIndex);
+            LOG_INFO("线程 {} 恢复成功", threadInfo.name);
+        } else {
+            LOG_ERROR("线程 {} 没有设置重启函数", threadInfo.name);
+        }
+    } catch (const std::exception& e) {
+        LOG_ERROR("恢复线程 {} 失败: {}", threadInfo.name, e.what());
+    } catch (...) {
+        LOG_ERROR("恢复线程 {} 时发生未知异常", threadInfo.name);
+    }
+}

+ 77 - 0
ThreadGuardian/ThreadGuardian.h

@@ -0,0 +1,77 @@
+#ifndef THREADGUARDIAN_H
+#define THREADGUARDIAN_H
+
+#include <thread>
+#include <mutex>
+#include <atomic>
+#include <unordered_map>
+#include <functional>
+#include <string>
+#include <chrono>
+
+// 前向声明
+class MppManager;
+class RKNNManager;
+
+// 线程状态结构体
+struct ThreadInfo {
+    int threadIndex;                // 线程索引
+    std::string name;                 // 线程名称
+    std::thread::id threadId;         // 线程ID
+    bool isRunning;                   // 线程是否正在运行
+    std::chrono::steady_clock::time_point lastAliveTime; // 上次活跃时间
+    std::function<void(int)> restartFunc; // 重启函数
+};
+
+class ThreadGuardian {
+public:
+    // 单例模式获取实例
+    static ThreadGuardian &getInstance() {
+        static ThreadGuardian instance;
+        return instance;
+    }
+
+    // 禁止拷贝和赋值
+    ThreadGuardian(const ThreadGuardian &) = delete;
+    ThreadGuardian &operator=(const ThreadGuardian &) = delete;
+
+    // 启动监控
+    void startMonitoring();
+    
+    // 停止监控
+    void stopMonitoring();
+    
+    // 注册MppDecoder线程
+    void registerMppThread(int threadIndex, std::function<void(int)> restartFunc);
+    
+    // 注册AIManager线程
+    void registerAIThread(int threadIndex, std::function<void(int)> restartFunc);
+    
+    // 线程心跳更新
+    void updateThreadHeartbeat(std::string threadName);
+    
+    // 移除线程监控
+    void unregisterThread(std::string threadName);
+
+private:
+    // 私有构造函数
+    ThreadGuardian();
+    ~ThreadGuardian();
+    
+    // 监控线程函数
+    void monitorThreads();
+    
+    // 恢复线程
+    void restartThread(const ThreadInfo& threadInfo);
+
+private:
+    std::thread m_monitorThread;              // 监控线程
+    std::atomic<bool> m_running;              // 监控线程运行标志
+    std::mutex m_threadMapMutex;              // 线程映射锁
+    std::unordered_map<std::string, ThreadInfo> m_threads; // 线程信息映射
+    
+    const std::chrono::seconds m_checkInterval{5};  // 检查间隔时间
+    const std::chrono::seconds m_threadTimeout{15}; // 线程超时时间
+};
+
+#endif // THREADGUARDIAN_H

+ 1 - 2
UVCGrabber/UVCCallBack.cpp

@@ -48,7 +48,7 @@ void cbSaveToLocal(uvc_frame_t *frame, void *ptr)
 
     if (!g_gpioExplorer->getFailingStatus(index))
     {
-      // std::cout << "Pass this wave" << std::endl;
+      //std::cout << "Pass this wave in channel " << index << std::endl;
       break;
     }
     g_gpioExplorer->resetFailingStatus(index);
@@ -58,7 +58,6 @@ void cbSaveToLocal(uvc_frame_t *frame, void *ptr)
     //   break;
     // }
 
-
     if (jpeg_count[index] / 23 >= 1)
       jpeg_group[index]++;
     jpeg_count[index] = jpeg_count[index] % 23;

+ 6 - 4
main.cpp

@@ -5,6 +5,7 @@
 #include "LogRecorder/LogOutput.h"
 #include "DataManager/DataManager.h"
 #include "DataManager/DataPackage.h"
+#include "ThreadGuardian/ThreadGuardian.h"
 #include "ImageTest/ImageTest.h"
 #include <stdexcept>
 #include <iostream>
@@ -43,13 +44,13 @@ int main(int argc, char **argv)
     if (OmniLoger::CLoger::get_instance().log_sink != nullptr)
     {
         std::cout << "Log initialized successfully" << std::endl;
-        //OmniLoger::CLoger::get_instance().log_sink->error("Error occurred during initialization");
+        // OmniLoger::CLoger::get_instance().log_sink->error("Error occurred during initialization");
     }
 
     // Initialize the UVC manager
     UVCManager::getInstance().init(int(config["usb_grab_waiting_time"]));
 
-
+    ThreadGuardian::getInstance().startMonitoring();
 
     UVCManager::getInstance().setDeviceNumber(0, config["usb_device_number"][0]);
     UVCManager::getInstance().setDeviceNumber(1, config["usb_device_number"][1]);
@@ -67,8 +68,9 @@ int main(int argc, char **argv)
     OmniLoger::CLoger::get_instance().log_sink->info("All streaming started successfully");
 
     // Wait for the user to press a key
-    while(true){
-     std::this_thread::sleep_for(std::chrono::seconds(1));
+    while (true)
+    {
+        std::this_thread::sleep_for(std::chrono::seconds(1));
     }
     // std::cin.get();