C++ - 退出主线的最佳方式

C++ - Best way to exit from main

本文关键字:最佳 方式 退出 C++      更新时间:2023-10-16

在我的主函数中,有一些对象在后台工作,直到析构函数被调用,如以下代码片段所示:

#include <iostream>
class MyBackground {
public:
    MyBackground()
    {
        m_workerThread = std::thread(&MyBackground::work, this);
    }
    ~MyBackground()
    {
        g_exit = true;
        workerThread.join();
    }
private:
    void work()
    {
        while(!m_exit);
    }
private:
    std::atomic<bool> m_exit{false};
    std::thread m_workerThread;
};

int main(int argc, char* argv[])
{
    MyBackground object;
    // here ther's some async background work
    return EXIT_SUCCESS;
    // ~MyBackground -> here threads are stopped
}

我需要一种方法来阻止主,直到出现一些外部信号。我的第一次尝试是这样的:

#include <csignal>
#include <iostream>
#include <thread>
using namespace std
atomic<bool> g_Exit{false};
void signalExit(int)
{
    g_Exit = true;  
}
int main(int argc, char* argv[])
{
    signal(SIGINT, signalExit);
    signal(SIGTERM, signalExit);
    MyBackground object;
    while (!g_Exit)
        this_thread::sleep_for(chrono::seconds{1});
    // here ther's some async background work
    return EXIT_SUCCESS;
    // ~MyBackground -> here threads are stopped
}

但我不确定这是否有效。我认为最好使用condition_variables如下代码段:

#include <csignal>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std
bool g_exitFlag = false;
condition_variable g_exitCondition;
mutex g_exitMutex;
using Lock = unique_lock<mutex>;
void signalExit(int)
{
    Lock lock{g_exitMutex};
    g_exitFlag = true;
    g_exitCondition.notify_one();
}
int main(int argc, char* argv[])
{
    signal(SIGINT, signalExit);
    signal(SIGTERM, signalExit);
    MyBackground object;
    Lock lock{g_exitMutex};
    g_exitCondition.wait(lock, [](){return g_exitFlag;});
    // here ther's some async background work
    return EXIT_SUCCESS;
    // ~MyBackground -> here threads are stopped
}

哪个最佳实现是正确的。他们正确吗?我不是多线程编程的"专家"。

为什么不采用稍微不同的设计,即 MyBackground 类不会创建和销毁后台工作线程,而是在 main 函数中创建线程?然后,main函数可以在线程退出之前简单地在线程上调用join,并且它将阻塞,直到后台线程完成。

类似的东西

class MyBackground {
public:
    void work()
    {
        while(!m_exit)
        {
            // Do background work
        }
    }
private:
    std::atomic<bool> m_exit{false};
};
int main()
{
    MyBackground background;
    std::thread background_thread(&MyBackground::work, background);
    // Do foreground work
    background.join();  // Wait for background to exit
    // Implicit return
}

如果线程应该在 main 函数返回时继续,另一种解决方案是分离线程。然后它将独立于主线程工作,并且在线程退出之前,进程不会真正退出。

请注意,这要求 main 函数不只是返回或exit,因为这将结束包括杀死所有线程在内的进程。相反,您只需退出"主"线程。不幸的是,使用标准C++线程接口无法做到这一点,但您必须使用平台本机函数。例如,在POSIX系统(如macOS和Linux)上,您使用pthread_exit .

您可以简单地在main()中使用std::weak_ptr来检查强引用计数是否为零以终止。将唯一的强引用指针传递给其他线程,以使 main() 能够顺利退出。请改用 std::conditon_variable 以避免关闭等待的线程,condition_variable轮询期间减少 CPU 使用率,以检查weak_ptr是否过期。

void worker_thread(std::shared_ptr<int>& pulse)
{
    // do something
    std::this_thread::sleep_for(std::chrono::seconds(2));
    pulse.reset(); // reset to terminate main() too from any other threads
  }
void main()
{
    std::shared_ptr<int> pulse = std::make_shared<int>(1);
    std::weak_ptr<int> weak_pulse(pulse);
    std::thread([&](){ worker_thread(pulse); }).detach();
    while (auto strong = weak_pulse.lock())
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
}