2013-12-19 6 views
9

私はチャットサーバーを開発しており、質問があります。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!"); 
} 

私は非常に疑問に思っています。 私を助けてください。 ありがとうございます。

+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

@BombPenguin:祈る。 VMで実行される管理対象言語とは異なり、C++ではコードを注入することはできません。したがって、動作がコード化されていない場合(使用しているライブラリまたはライブラリによって)、それは起こりません。ここではBoostを使用しているので、アクセプタとソケットのドキュメントを見直して、他のスレッドからのすべての操作を安全に終了するように通知できるかどうかを確認する必要があります。 –

3

std :: threadを安全に停止する方法を教えてください。

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

response from @DietmarKuhlは、これを行う方法を説明しています。ブロックされている受け入れに関しては、ソケット/アクセプタのオプションをタイムアウト時に期限切れにするように設定する必要があります。 accept呼び出しが返ってくると、ループが壊れている(ループ条件がfalseの場合)か、新しいタイムアウトでacceptに再度呼び出します。

あなたのタイムアウト値は妥協点です。小さなタイムアウトは、非常に応答性の高いスレッド機能(スレッドを停止するときにあまりブロックしない機能)を提供しながら、より計算集約的です(CPUをビジーに保ちます)。

+2

そのルートに行く前に、ソケットを閉じたり、別のスレッドからアクセプタをファイナライズすることができるかどうかを調べたいかもしれません。 –

+0

私はそれを考慮していなかった(+1);それは良い解決策ですが、コードを見ても明示的ではないので(私はまだソケット上のタイムアウトを使用して受け入れるか受け入れるかのどちらか)、考慮しません。 – utnapistim

+0

ソケットのタイムアウトは、とにかく、無限にぶら下がることを避けるために、おそらく良い考えです。終了/終了という考えは、それが(比較的)即時であるということです。 –

関連する問題