web-dev-qa-db-ja.com

stdスレッドを安全に停止する方法は?

チャットサーバーを開発していますが、質問があります。

停止する方法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!");
}

とても不思議です。私を助けてください。ありがとうございました。

12
BombPenguin

アクセプターを閉じると、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
Mike Seymour

適切なコンテキストをスレッドに渡すことができます。このコンテキストには、停止する時間かどうかを示すフラグを含めることができます。フラグはstd::atomic<bool>。もちろん、データを無期限に待たないように通信を設定する必要があるので、たまにフラグをチェックする機会があります。

9
Dietmar Kühl

Std :: threadを安全に停止する方法は?

スレッドを安全に停止するということは、スレッド関数に処理を停止するように指示し(std::threadの外部にあるメカニズムを介して)、スレッドが停止するのを待つことを意味します。

@ DietmarKuhlからの応答 は、これを行う方法を示しています。アクセプトがブロックされていることに関して、タイムアウトで期限切れになるようにソケット/アクセプターにオプションを設定する必要があります。 accept呼び出しが戻ったら、ループを中断するか(ループ条件が偽の場合)、新しいタイムアウトを使用してacceptを再度呼び出します。

タイムアウト値は妥協点になります。タイムアウトが小さいと、計算量が多くなり(CPUをビジー状態に保ちます)、応答性の高いスレッド関数(スレッドを停止してもあまりブロックされない関数)が得られます。

3
utnapistim