2013-12-19 186 views
9

我正在开发一个聊天服务器,我有一个问题。如何安全停止std::thread如何安全地停止std线程?

这是很容易的问题,像这样。

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!"); 
} 

我非常想知道。 请帮帮我。 谢谢。

+1

'join'实际上工作得很好。它记录了阻止行为的事实并不意味着它不起作用。 – chris

+1

我相当肯定,关闭受体应该引起呼叫'accept'抛出一个异常,并退出循环。直到加入线程之后才删除接受者。 –

+0

设置条件变量和加入,线程需要检查的条件变量和清理和死,如果它被设置 –

回答

3

我相当确信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 
} 

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

7

您可以将适当的上下文传递给可包含指示是否该停止的标志的线程。国旗可以是std::atomic<bool>。显然,你还需要建立沟通,不要无限期地等待数据,所以你有机会偶尔检查一下标志。

+0

谢谢。但是,m_Acceptor.accept()是块模式。如果我调用了这个函数,它就会阻塞。我该怎么办? – BombPenguin

+0

@炸弹企鹅:祈祷。与VM中运行的托管语言不同,C++不允许您注入代码;所以如果行为没有被编码(或者你或者你正在使用的库),那么它就不会发生。由于您在这里使用的是Boost,因此您应该查看acceptor和socket的文档,并检查是否可以发信号通知他们安全地终止来自另一个线程的所有操作。 –

3

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

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

response from @DietmarKuhl告诉你如何做到这一点。关于拦截的概念,您必须在套接字/接受器上设置一个选项,以在超时时间结束。当接受呼叫返回时,您要么中断循环(如果您的循环条件为false),要么再次呼叫accept,并发生新的超时。

您的超时值将是一个折中:小的超时会在计算上占用更多的时间(保持CPU繁忙),同时给您一个非常灵敏的线程函数(当您停止线程时不会阻塞太多)。

+2

在进行该路由之前,您可能需要检查是否可以关闭套接字,而不是从另一个线程完成接受程序。 –

+0

我甚至没有考虑过(+1);这是一个很好的解决方案,但是在查看代码时我不会考虑它,因为它不是以任何方式显式的(所以我可能仍然使用套接字或接受上的超时来实现这一点)。 – utnapistim

+0

无论如何,套接字中的超时值可能是一个好主意,以避免无限期悬挂;关闭/终止的想法是(相对)直接。 –