2013-12-19 244 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

無論如何,套接字中的超時值可能是一個好主意,以避免無限期懸掛;關閉/終止的想法是(相對)直接。 –