C ++でのスレッドプール設計

私はこの質問をどのようにこのフォーラムに入れて、私が尋ねるところで何らかのインプットを得ることを望む方法はわかりません。

私は私のプロジェクトのスレッドプールを作成しています。私は次のデザインを持っています。

  1. I am maintaining vector of threads std::vector<threadWrapper <threadFuncParam>* > m_vecThreads;

  2. and pushing the threds in to list m_vecThreads.push_back(pThreadWrapper);

  3. When new request comes i am taking the thread pool as below

    if(!m_vecThreads.empty() )
    {
        ThreadWrapper <threadFuncParam>* pWrapper = m_vecThreads.back();
        m_vecThreads.pop_back();
        //... Awake threadd
    }
    
  4. When thread job is done it is pushed back in to pool of thread.

今ではgracefullシャットダウン私は問題を直面している上記の設計と優雅に今すぐスレッドを停止しているどのようにベクトルコンテナでスレッドを停止することができます私はベクトルから要求がサービスされるので、サービスが完了するまでポインタを失った。 私はこれを行うことができるか、標準のC ++でサポートされているマップや他のコンテナのようなこのシナリオを処理する方が良いでしょうか?

もう一つの質問は

シャットダウン時には、シナリオスレッドが私の場合、データベースからの読み込みに時間がかかる可能性があるので、ここでプロセスを実行しています。完了するまで待つことはできません スレッドが処理中で、その値を強制終了しようとしている保留中の要求に対してクライアントに返信したいと思っています。

ありがとう!

2
あなたが持っているものは、スレッドのベクトルではなく、スレッドへのポインタのベクトルです。どのようにスレッド自体をインスタンス化するのですか? new で手動で行いますか?スレッドラッパーを別のコンテナに格納することを検討してください。 std :: vector <threadWrapper <threadFuncParam>> を実行し、これらのスレッドのアドレスを m_vecThreads にします。
追加された 著者 leftaroundabout,
あなたの "別の質問"は本当の他の質問として尋ねられるべきです+あなたの他の質問の問題が何であるかは不明です。
追加された 著者 stefaanv,

4 答え

プールから渡したものに引き続きアクセスする必要がある場合は、アイテムを「使用済み」コンテナに格納する必要があります。
しかし、その時点でポインタを共有しているので、shared_ptrを使用してweak_ptrを渡す必要があります。そのため、スレッドも削除することができ、ユーザにはダングリングポインタはありません

使用されたアイテムの最良のコインタイターはセットになるため、返されたスレッドは簡単に見つけて削除できます。

1
追加された

あなたの最初の問題を解決するには、別のベクタ、たとえば m_vecBusyThreads にプッシュしてください。終了したら、そこから取り除いてください(完成したスレッドを検索するメカニズムが必要です) 。

あなたの2番目の問題は、最もクリーンな解決策は、 "シャットダウン"を持っているまで、各スレッドに参加する任意の他のアプローチは、いくつかの望ましくない副作用(espは、例えば、データベースに接続している場合など)それぞれの空きコンテナを繰り返し、各スレッドをシャットダウンして結合します。その後、ビジー状態のコンテナに戻り、各スレッドに参加しようとします。これはビジースレッドにシャットダウンするのに少し時間を与えるかもしれません。

boost :: threadsはこのような割り込みポイントの概念をサポートしていますが、これらのポイントのいずれかでスレッドを中断できますが、いくつかの呼び出しは中断できません(通常は呼び出しをブロックします) (例えばソケット読み込みは、ダミーパケットなどを送るかもしれない)

0
追加された

私はCで行っているので、解決策は "C ++"ではありませんが、2つの配列を使用していました:1つはスレッドを含み、もう1つはused/unused(〜boolean)の表現を含みます。

私は次のようなものになります:

pthread_t[INITIAL_SIZE] thread_pool;
boolean[INITIAL_SIZE] threads_availability;
int first_available = 0;

pthread_t * get_thread() {
   int ind = 0;
   if (first_available<=INITIAL_SIZE) {
      ind = first_available;
     //find the next available spot
      for (first_available; first_available < INITIAL_SIZE && threads_availability[first_available]; first_available++);
      threads_availability[ind] = 0;

      return thread_pool[ind];
   }
}

void put_thread(pthread_t* thethread)
{
    int i = 0;
    pthread_t *it = thread_pool;
    while (!pthread_equals(it, thethread)) {
        it++;
        i++;
    }
    thread_availability[i] = 1;
}

これは擬似コードであり、これは最適ではないことに注意してください。 しかしこれは考えです。

0
追加された
使用済みのアイテムを別のコンテナに入れるのにはオーバーヘッドがありますが、このソリューションは大きなプールでは非常にコストがかかる可能性があります。
追加された 著者 stefaanv,

これは、他の人が既にあなたの元の質問に答えているので、あなたの問題に対する直接的な答えではありません。

boost :: asioやboost :: threadを調べることができたと言いたいだけです。 私はおそらくboost :: asioに行くだろう。なぜなら、タイマーやその他のものに基づいて非同期操作を行うために必要なものがすべてあるからだ。 shared_ptrとboost :: enable_shared_from_thisを使って、自分の仕事を終わらせて自動的に破壊することができます。

例:

boost::shared_ptr aj( new async_job(
   io_, boost::bind(&my_job::handle_completion, shared_from_this(), _1, _2)));

このコードは、スレッドプール上でカスタムasync_jobを実行します(io_はboost :: asio :: io_serviceです)。あなたの 'my​​_job'インスタンスは、async_jobが終了すると自動的に破棄され、handle_completionが呼び出されます。 handle_completionの中でshared_from_this()をもう一度実行すると、それを放置することができます。

HTH、 アレックス

0
追加された