【问题标题】:How to stop std thread safely?如何安全地停止 std 线程?
【发布时间】:2013-12-19 12:27:40
【问题描述】:

我正在开发一个聊天服务器,我有一个问题。

如何安全地停止std::thread

这是很简单的问题,像这样。

thread t(&func);
t.join();

但是,如果 func 有无限循环,则连接不起作用。

这是我的来源。

void CServerSocket::AcceptRun(boost::asio::io_service &iosrv)
{
    while (true)
    {
        auto sock = std::make_shared<boost::asio::ip::tcp::socket>(iosrv);
        m_Acceptor->accept(*sock);

        m_SocketList.push_back(std::make_shared<CConnectionSocket>(this, sock));
    }
}

CServerSocket::~CServerSocket()
{
    CLogManager::WriteLog("Stopping Server...");
    m_Acceptor->close();
    m_Acceptor.reset();

    // m_AcceptThread.detach(); This is right?

    CLogManager::WriteLog("Server Stoped!");
}

我很想知道。 请帮我。 谢谢。

【问题讨论】:

  • join 实际上效果很好。它记录了阻塞行为的事实并不意味着它不起作用。
  • 我很确定关闭接受器应该会导致对accept 的调用抛出异常并退出循环。在加入线程之前不要删除接受者。
  • 设置条件变量并加入,线程需要检查条件变量并清理,如果它被设置则死亡
  • 嗯,我也试过调用join(),但是出现错误“Debug error! R6010 abort() has been called
  • 迈克·西摩//哇,谢谢。 join() 非常完美!!!感谢分享。

标签: c++ multithreading join boost-asio


【解决方案1】:

您可以将合适的上下文传递给您的线程,其中可以包含一个指示是否该停止的标志。该标志可以是std::atomic&lt;bool&gt;。显然,您还需要设置通信以不无限期地等待数据,以便您有机会偶尔检查标志。

【讨论】:

  • 谢谢。但是, m_Acceptor.accept() 是块模式。如果我调用该函数,它会阻塞。我该怎么办?
  • @BombPenguin:祈祷。与在 VM 中运行的托管语言不同,C++ 不允许您注入代码。因此,如果行为未编码(由您或您正在使用的库),则不会发生。由于您在这里使用的是 Boost,因此您应该查看接受器和套接字的文档,并检查您是否可以向它们发出信号以安全地终止来自另一个线程的所有操作。
【解决方案2】:

我相当确定accept 会在您关闭接受器时干净地退出并抛出异常。您应该捕获异常,以便线程正常退出:

void CServerSocket::AcceptRun(boost::asio::io_service &iosrv)
try {
    // your loop here, unchanged
} catch (std::exception const & ex) {
    // perhaps log the message, ex.what()
}

然后在关闭接收器之后加入线程,但在销毁它之前:

CServerSocket::~CServerSocket()
{
    CLogManager::WriteLog("Stopping Server...");
    m_Acceptor->close();
    m_AcceptThread.join();
    CLogManager::WriteLog("Server Stopped!");

    // No need to do anything else with m_Acceptor, assuming it's a smart pointer
}

就个人而言,我会使用异步操作,除非有令人信服的理由使用多个线程。单线程更容易处理。

【讨论】:

    【解决方案3】:

    如何安全地停止 std::thread?

    安全停止线程意味着您告诉线程函数停止处理(通过std::thread 之外的机制),然后等待线程停止。

    response from @DietmarKuhl 告诉您如何执行此操作。关于接受阻塞,您必须在套接字/接受器上设置一个选项以在超时时过期。当 accept 调用返回时,您要么中断循环(如果您的循环条件为 false),要么再次调用 accept,并设置一个新的超时时间。

    您的超时值将是一个折衷方案:较小的超时将更加计算密集(使 CPU 保持忙碌),同时为您提供一个响应速度非常快的线程函数(当您停止线程时不会阻塞太多)。

    【讨论】:

    • 在走这条路之前,您可能想检查是否可以关闭套接字/从另一个线程完成接受器。
    • 我什至没有考虑过(+1);这是一个很好的解决方案,但在查看代码时我不会考虑它,因为它在任何方面都不是明确的(所以我可能仍然会使用套接字超时或接受来实现它)。
    • 无论如何,套接字超时可能是个好主意,以避免无限期挂起;关闭/终止的想法是它(相对)立即。
    猜你喜欢
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-10
    相关资源
    最近更新 更多