3

私は pthreaded ネットワーク アプリケーションを (C で) 作成しており、各着信接続を処理するスレッドを作成する必要があると考えていました。ただし、接続数を固定数 (たとえば 5) に制限する必要があるため、どの設計を使用すればよいかわかりません。

pthread_join の man ページを読んでいるときに、次のことがわかりました。

There is no pthreads analog of waitpid(-1, &status, 0), that  is,  "join  with  any terminated
thread". If you believe you need this functionality, you probably need to rethink your
application design.

どうしてこれなの?そして、どうすれば私の目標を達成できますか? ありがとう

4

5 に答える 5

1

いい質問ですね。

マニュアルページの作成者が得ている標準的な理由は、プロセスを刈り取る必要があるwaitpidか、リソースを残しておく必要があるということだと思います。これは、pthreadの場合は実際には当てはまりません。特定のスレッドがいつ終了するかを知る必要がない場合(またはその戻りコードが必要ない場合)は、それを切り離されたスレッドにすることができます。それは終わり、それだけです。逆に、本当にスレッドに参加する必要がある場合は、どのスレッドに参加する必要があるかを知っておく必要があります。

さらに考えてみると、親プロセスとその子の間には直接的な1対多の関係があります。 Waitpidはその子を待機し、OSはそれらの子を追跡して親に配信します。これは、プロセスの世代数に関係なく発生します。親は子を刈り取ります。

スレッド化されたプログラムでは、どのスレッドでも他のスレッドを作成できます。pthread_joinこの場合、キャッチオールはどういう意味ですか?すべてのスレッドがこの1つのキャッチオールスレッドに結合されることを意図している場合は、すべて問題ありません。しかし、残りのスレッドがキャッチオールによって結合されても問題がないのに、一部のスレッドをその子スレッドと実際に結合する必要があるプログラムについてはどうでしょうか。joinOSまたはpthreadは、実質的なインフラストラクチャを構築せずに、それぞれの場合にどちらが適用される かをどのように追跡しますか?

それは可能だと思いますwaitpid。pthreadに一般的なアナログが含まれていることを誰もが望んでいたと思いますが、実際にはほとんどの場合、煩わしさのために多くのオーバーヘッドが発生する可能性があります。参加するスレッドが複数あるが、どれが最初に終了するかわからない状況に陥った場合は、キューを作成して(またはパイプなどを使用して)、死にかけているスレッドに参加するように指示させることができます。 。

于 2012-08-06T05:32:02.073 に答える
0

スレッドはプロセスのように階層に編成されていないため、「任意の」スレッドを待機することは、任意のスレッドがすべてのスレッドに関するグローバル情報にアクセスできることを意味します。このような情報をある種のデータ構造(またはその他)で編成すると、すべてのスレッドの作成と終了がそこを通過する必要があるため、特定のオーバーヘッドが発生します。この種のオーバーヘッドは自発的に回避され、スレッドは軽量で高速になるようになっています。

結合すらできないスレッド、つまり、最初から切り離されたスレッドや切り離されたスレッドがあるという別の側面もあります。それらにそのようなオーバーヘッドを課すことはさらに受け入れられないでしょう。

于 2012-08-06T06:51:37.490 に答える
0

同時スレッドの数に制限を設ける場合、最善の策は、前もってすべてのスレッド (ワーカー) を頻繁に作成し、それらを無限ループで実行させ、キューで作業を待機させることです。

次に、メイン スレッドは、ワーカーが処理するための作業項目 (この場合は接続) をそのキューに追加する役割を果たします。

これの利点は、単純さと速度です。スレッドの開始または停止について 1 回を除いて心配する必要がないため、シンプルです。スレッドは常に実行されており、作業項目にサービスを提供しています。

同じ理由でスピード。これは、固定サイズのスレッド プールのようなものです。また、ワークアイテムを最も効率的な方法で処理します (スレッドが前のアイテムを終了したときにのみ新しいアイテムを要求するため、ワークロードは自動的にバランスが取れます)。

擬似コードでは、これは次のようになります。メインラインは、作業項目が入ってくるとキューに追加するだけです。すべてが完了すると、各スレッドに特別な仕上げ作業項目をポストして、すべてが完了するのを待ちます。

def queue workqueue = empty

def main:
    # start the threads

    create threadId[5]
    for each threadId (i):
        threadId[i] = startThread (worker)

    # main work loop, finished with (for example) external signal.

    while not finished:
        get workitem from some source
        add workitem to workqueue

    # Place one special FINISH work item for each thread.

    for each threadId (i):
        add FINISH item to workqueue

    # Wait for all threads to exit, then exit main.

    for each threadId (i):
        wait for threadId[i] to exit

    exit

ワーカー スレッドも同様に単純です。必要に応じて作業項目を取得して処理するための無限ループ。

作業項目が仕上げの場合、終了し、各スレッドが 1 つの仕上げ作業項目のみを取得することが保証されます。

def worker:
    # Simple infinite loop to get work items.

    while true:
        get workitem from workqueue

        # Exit if told to.

        if workitem is a FINISH item:
            break

        # Otherwise, process the item and loop around to request next.

        process workitem

    exit
于 2012-08-06T02:07:07.290 に答える
0

スレッドの終了と再起動を許可するのではなく、スレッドを永続的なままにすることを許可するというpaxdiabloの提案を最初にエコーさせてください。さらに、ノンブロッキング I/O を使用するという selbie の提案に同意しますが、それを固定スレッドと結合します (CPU ごとに 1 つだけだと思います)。両方を使用すると、はるかに高いワークロードを実現し、マシンの CPU リソースを最大化できます。

ただし、質問に答えるには、終了順序でスレッドに参加できるようにする場合は、スレッドがリーパーと終了順序を通信する必要があります。これは、 を使用して比較的簡単に実行できますpipe。スレッドが終了すると、そのスレッドtidがパイプに書き込まれ、リーパーが読み取り、tid実行しpthread_joinます。

int tid_pipe[2];
pipe(tid_pipe);

void * thread_proc (void *arg) {
    /* ... */
    /* thread exiting */
    pthread_t me = pthread_self();
    write(tid_pipe[1], &me, sizeof(me));
    return 0;
} 

/* thread reaper */
while (read(tid_pipe[0], &tid, sizeof(tid)) == sizeof(tid)) {
    pthread_join(tid, &retval);
    /* ... */
}

ただし、別の方法として、スレッドを切り離して実行し、結合について心配する必要はありません。代わりに、条件変数を使用して、メイン スレッドがいつ別のスレッドを起動してもよいかを認識できるようにすることができます。

void * thread_proc (void *arg) {
    pthread_detach(pthread_self());
    /* ... */
    /* thread exiting */
    pthread_mutex_lock(&m);
    if (thread_count++ == 0) pthread_cond_signal(&c);
    pthread_mutex_unlock(&m);
    return 0;
}

/* thread spawner */
while (waiting_for_work()) {
    pthread_mutex_lock(&m);
    while (thread_count == 0) pthread_cond_wait(&c, &m);
    pthread_mutex_unlock(&m);
    /* ... handle work with new thread ... */
}
于 2012-08-06T05:53:31.990 に答える
-1

クライアントごとに 1 つのスレッドを持つマルチスレッド サーバーの場合は、それらを数えて、もう一度数え直してください。クライアント スレッドの作成時 (つまり、accept() スレッド内)、およびクライアント サーバー スレッドが終了する直前に、'clientCount' int のアトミックな inc/dec を使用し、カウントが 5 を超える場合はそれ以上の接続を受け入れません。 、(つまり、新しいサーバークライアントスレッドを作成する代わりに、accept()スレッドから直接「接続が多すぎます。後で試してください」ページを発行します)。

「Join」のことは忘れるようにしてください。それについて読んだことがないと想像してみてください。

于 2012-08-07T04:40:48.503 に答える