4

現在、特定の状況に応じてスレッドが作成される場合があるマルチスレッド プログラムを作成しています。このスレッドが作成された場合、他のすべてのスレッドとは独立して実行する必要があり、参加するのを待つために他のスレッドをブロックする余裕はありません。生成されたスレッドが実行される時間の長さはさまざまです。場合によっては数時間かかることもあります。

私はスレッドを生成し、正常に動作するクラスのデストラクタに結合を配置しようとしましたが、生成されたスレッド内のコードがデストラクタが呼び出される前に長い時間終了する場合 (これは約 99% の時間になります)スレッドが自分自身を殺し、そのすべてのリソースを解放するなど。

これにデタッチを使用することを検討しましたが、デタッチされたスレッドに再度参加することはできず、このスレッドが終了する前にデストラクタが呼び出された場合、生成されたスレッドは終了せず、悲惨な結果を招く可能性があります。

クラスが破棄される前にスレッドが終了することを保証し、スレッドが作業を終了するとすぐに参加できるようにする解決策はありますか?

スレッドにboost/c++11を使用しています。どんな助けでも大歓迎です。

ありがとう

4

2 に答える 2

4

スレッドはそれ自体を切り離し、そのリソースを解放する可能性があります。デストラクタがスレッドが結合可能である、つまりまだ実行中であることを確認した場合は、スレッドを結合させます。スレッドが終わりに達した場合は、セルフデタッチします。考えられる競合状態:is_joinable()はデストラクタでtrueを返します-スレッドはそれ自体をデタッチします-デストラクタは結合し、惨めに失敗します。したがって、スレッドの停止を保護するミューテックスを使用します。

struct ThreadContainer
{
   std::mutex threadEndMutex;
   std::thread theThread;

   ThreadContainer()
     : theThread([=]()
       {
         /* do stuff */

         // if the mutex is locked, the destructor is just
         // about to join, so we let him.
         if (threadEndMutex.try_lock())
           theThread.detach();
       })
   {}

   ~ThreadContainer()
   {
     // if the mutex is locked, the thread is just about 
     // to detach itself, so no need to join.
     // if we got the mutex but the thread is not joinable, 
     // it has detached itself already.
     if (threadEndMutex.try_lock() && theThread.is_joinable())
       theThread.join();
   }
};

PS:スレッドがそれ自体を切り離した場合、ミューテックスのロックが解除されず、try_lockが失敗するため、is_joinableを呼び出す必要がない場合もあります。

PPS:ミューテックスの代わりに、std :: atomic_flag:を使用できます。

struct ThreadContainer
{
   std::atmoic_flag threadEnded;
   std::thread theThread;

   ThreadContainer()
     : threadEnded(ATOMIC_FLAG_INIT)
     , theThread([=]()
       {
         /* do stuff */

         if (!threadEnded.test_and_set())
           theThread.detach();
       })
   {}

   ~ThreadContainer()
   {
     if (!threadEnded.test_and_set())
       theThread.join();
   }
};
于 2012-11-27T10:25:57.193 に答える
1

「独立した」スレッドアルゴリズムで一時停止/ステップを定義し、各ステップで、計算をキャンセルして自動破棄するか、スレッドで計算を続行するかを決定するのに役立つグローバル変数を確認できます。

グローバル変数が十分でない場合、つまり、より正確な粒度が必要な場合は、スレッド関数のファンクター オブジェクトを定義する必要があります。このファンクターにはメソッド kill() があります。ファンクターをスレッドとして起動した後、ファンクターの参照を保持します。MyThreadFunctor::kill() を呼び出すと、ブール フィールドが設定され、このフィールドはファンクター スレッド関数自体の計算の各ステップでチェックされます。

于 2012-11-27T10:12:53.673 に答える