diff --git a/src/main.cpp b/src/main.cpp index 02ba502..401e0ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,43 +6,29 @@ #include #include #include +#include // write, STDOUT_FILENO +#include std::atomic g_running(true); -// main.cpp - 修改signalHandler -void signalHandler(int signum) +static void minimal_signal_handler(int signum) { - static bool already_called = false; - if (already_called) - return; - already_called = true; - - LOG_INFO("[MAIN] Received signal " + std::to_string(signum) + ", shutting down..."); - g_running = false; - - // 停止RTSP循环 - RTSPManager::stop(); - - // 记录停止时间 - auto start_time = std::chrono::steady_clock::now(); - - // 等待一段时间让线程退出 - while (std::chrono::steady_clock::now() - start_time < std::chrono::seconds(3)) - { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - - LOG_INFO("[MAIN] Force exiting after waiting for threads"); - exit(1); + // 只做非常有限且 async-signal-safe 的操作 + g_running.store(false, std::memory_order_relaxed); + const char msg[] = "[MAIN] Signal received, initiating shutdown...\n"; + write(STDERR_FILENO, msg, sizeof(msg) - 1); + // 不要调用 LOG_*、malloc、std::string、mutex、exit 等 } int main() { - struct sigaction sigIntHandler; - sigIntHandler.sa_handler = signalHandler; - sigemptyset(&sigIntHandler.sa_mask); - sigIntHandler.sa_flags = 0; - sigaction(SIGINT, &sigIntHandler, NULL); + // 安装信号处理(SIGINT 和 SIGTERM) + struct sigaction sigAct{}; + sigAct.sa_handler = minimal_signal_handler; + sigemptyset(&sigAct.sa_mask); + sigAct.sa_flags = 0; + sigaction(SIGINT, &sigAct, nullptr); + sigaction(SIGTERM, &sigAct, nullptr); signal(SIGPIPE, SIG_IGN); // 初始化日志文件 @@ -59,31 +45,82 @@ int main() return -1; } + // 线程退出标志,用于超时等待 + std::atomic rtsp_thread_exited(false); + std::atomic mqtt_thread_exited(false); + // 先在主线程初始化 GStreamer RTSPManager::init(); std::thread rtsp_thread([&]() - { RTSPManager::start(g_app_config.cameras); }); - std::thread mqtt_thread(mqtt_client_thread_func); + { + RTSPManager::start(g_app_config.cameras); + rtsp_thread_exited.store(true, std::memory_order_relaxed); }); + + std::thread mqtt_thread([&]() + { + mqtt_client_thread_func(); + mqtt_thread_exited.store(true, std::memory_order_relaxed); }); // 等待退出信号 - while (g_running) + while (g_running.load(std::memory_order_relaxed)) std::this_thread::sleep_for(std::chrono::milliseconds(200)); - // 在main函数等待线程结束处添加日志 + LOG_INFO("[MAIN] Shutdown requested, stopping services..."); + + // 等线程优雅退出:总等待时间 (可调整) + const auto max_wait = std::chrono::seconds(5); + const auto poll_interval = std::chrono::milliseconds(100); + auto deadline = std::chrono::steady_clock::now() + max_wait; + + // 等 RTSP 线程退出 + while (!rtsp_thread_exited.load(std::memory_order_relaxed) && + std::chrono::steady_clock::now() < deadline) + { + std::this_thread::sleep_for(poll_interval); + } if (rtsp_thread.joinable()) { - LOG_INFO("[MAIN] Waiting for RTSP thread to finish..."); - rtsp_thread.join(); - LOG_INFO("[MAIN] RTSP thread finished"); + if (rtsp_thread_exited.load(std::memory_order_relaxed)) + { + rtsp_thread.join(); + LOG_INFO("[MAIN] RTSP thread finished and joined."); + } + else + { + LOG_WARN("[MAIN] RTSP thread did not exit within timeout."); + } + } + + // 等 MQTT 线程退出 + deadline = std::chrono::steady_clock::now() + max_wait; + while (!mqtt_thread_exited.load(std::memory_order_relaxed) && + std::chrono::steady_clock::now() < deadline) + { + std::this_thread::sleep_for(poll_interval); } if (mqtt_thread.joinable()) { - LOG_INFO("[MAIN] Waiting for MQTT thread to finish..."); - mqtt_thread.join(); - LOG_INFO("[MAIN] MQTT thread finished"); + if (mqtt_thread_exited.load(std::memory_order_relaxed)) + { + mqtt_thread.join(); + LOG_INFO("[MAIN] MQTT thread finished and joined."); + } + else + { + LOG_WARN("[MAIN] MQTT thread did not exit within timeout."); + } + } + + // 如果某些线程仍未退出,强制结束进程(不会跑全局析构) + if ((rtsp_thread.joinable() && !rtsp_thread_exited.load(std::memory_order_relaxed)) || + (mqtt_thread.joinable() && !mqtt_thread_exited.load(std::memory_order_relaxed))) + { + LOG_ERROR("[MAIN] Threads did not exit in time. Forcing immediate termination."); + _exit(1); // 强制退出(不会调用 atexit handlers) } LOG_INFO("[MAIN] Program exited cleanly."); + return 0; } \ No newline at end of file