web-dev-qa-db-ja.com

pthreadを照会して、まだ実行中かどうかを確認するにはどうすればよいですか?

私のデストラクタでは、スレッドをきれいに破壊したいです。

私の目標は、スレッドの実行が完了するのを待ってから、スレッドを破棄することです。

Pthreadの状態を照会することに関して私が見つけた唯一のことは pthread_attr_setdetachstate ですが、これはあなたのスレッドが次の場合にのみ教えてくれます:

  • PTHREAD_CREATE_DETACHED
  • PTHREAD_CREATE_JOINABLE

どちらも、スレッドがまだ実行中かどうかとは関係ありません。

pthreadを照会して、まだ実行中かどうかを確認するにはどうすればよいですか?

49

ここには2つの質問があるようです。

スレッドが完了するまで待つにはどうすればよいですか?

回答:これはpthreadによって直接サポートされています-停止するスレッドを(最初に起動したときに)JOINABLEにし、pthread_join()を使用して、停止するスレッドがなくなるまで現在のスレッドをブロックしますランニング。


スレッドがまだ実行されているかどうかを確認するにはどうすればよいですか?

回答:「thread_complete」フラグを追加して、トリックを行うことができます。

シナリオ:スレッドAは、スレッドBがまだ生きているかどうかを知りたいと考えています。

スレッドBが作成されると、「thread_complete」フラグアドレスへのポインターが与えられます。 「thread_complete」フラグは、スレッドが作成される前にNOT_COMPLETEDに初期化される必要があります。スレッドBのエントリポイント関数は、すぐにpthread_cleanup_Push()を呼び出して、「thread_complete」フラグをCOMPLETEDに設定する「cleanup handler」をプッシュする必要があります。

クリーンアップハンドラーの詳細については、こちらをご覧ください: pthread cleanup handlers

対応するpthread_cleanup_pop(1)呼び出しを含めて、クリーンアップハンドラーが何に関係なく呼び出されるようにします(つまり、スレッドが正常に終了する場合は、OR)。).

次に、スレッドAは単に「thread_complete」フラグをチェックして、スレッドBがまだ終了しているかどうかを確認できます。

注:「thread_complete」フラグは「volatile」と宣言し、アトミックタイプにする必要があります-GNUコンパイラーはこの目的のためにsig_atomic_tを提供します。これにより、2つのスレッドが同じデータに一貫してアクセスできます同期コンストラクト(ミューテックス/セマフォ)は必要ありません。

38
jeremytrimble
pthread_kill(tid, 0);

シグナルは送信されませんが、エラーチェックが実行されるため、それを使用してtidの存在を確認できます。

[〜#〜] caution [〜#〜]:この答えは間違っています。この規格では、ライフタイムが終了したスレッドのIDを渡すことを特に禁止しています。そのIDは現在、別のスレッドを指定している可能性があり、さらに悪いことに、解放されたメモリを参照してクラッシュを引き起こしている可能性があります。

30
pthread_kill

本当に必要なのはpthread_join()を呼び出すことだけだと思います。その呼び出しは、スレッドが終了するまで戻りません。

スレッドがまだ実行されているかどうかを確認するためだけにポーリングしたい場合(そして、通常はあなたがしたいことではないことに注意してください!)、終了する直前にスレッドにvolatileブール値をfalseに設定させることができます。メインスレッドはブール値を読み取ることができ、それでもtrueであれば、スレッドがまだ実行されていることがわかります。 (一方、falseの場合、スレッドは少なくともほとんどなくなっていることがわかります。ブール値をfalseに設定した後に発生するクリーンアップコードを実行している可能性がありますので、この場合でも前にpthread_joinを呼び出す必要がありますスレッドがアクセスできる可能性のあるリソースを解放しようとしています)

8
Jeremy Friesner

完全に移植可能なソリューションはありません。プラットフォームがpthread_tryjoin_npまたはpthread_timedjoin_npをサポートしているかどうかを確認してください。したがって、スレッドを結合できるかどうかを確認するだけです(もちろん、PTHREAD_CREATE_JOINABLEで作成されます)。

5
Dewfy

少なくともLinuxで機能するソリューションを思いついたと思います。スレッドを作成するたびに、LWP(ライトウェイトプロセスID)を保存し、一意の名前を割り当てます。 int lwp = syscall(SYS_gettid); prctl(PR_SET_NAME、(long) "unique name"、0、0、0);

その後、スレッドが後で存在するかどうかを確認するために、/ proc/pid/task/lwp/commで読みます。ファイルが存在し、その内容が割り当てた一意の名前と一致する場合、スレッドが存在します。これは、おそらく無効/再利用されたTIDをライブラリ関数に渡さないため、クラッシュしないことに注意してください。

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/file.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <syscall.h>

pthread_t subthread_tid;
int       subthread_lwp;

#define UNIQUE_NAME "unique name"

bool thread_exists (pthread_t thread_id)
{
    char path[100];
    char thread_name[16];
    FILE *fp;
    bool  thread_exists = false;

    // If the /proc/<pid>/task/<lwp>/comm file exists and it's contents match the "unique name" the
    // thread exists, and it's the original thread (TID has NOT been reused).

    sprintf(path, "/proc/%d/task/%d/comm", getpid(), subthread_lwp);

    fp = fopen(path, "r");

    if( fp != NULL ) {

        fgets(thread_name, 16, fp);
        fclose(fp);

        // Need to trim off the newline
        thread_name[strlen(thread_name)-1] = '\0';

        if( strcmp(UNIQUE_NAME, thread_name) == 0 ) {
            thread_exists = true;
        }
    }

    if( thread_exists ) {
        printf("thread exists\n");
    } else {
        printf("thread does NOT exist\n");
    }

    return thread_exists;
}


void *subthread (void *unused)
{
    subthread_lwp = syscall(SYS_gettid);
    prctl(PR_SET_NAME, (long)UNIQUE_NAME, 0, 0, 0);

    sleep(10000);

    return NULL;
}


int main (int argc, char *argv[], char *envp[])
{
    int error_number;

    pthread_create(&subthread_tid, NULL, subthread, NULL);
    printf("pthread_create()\n");
    sleep(1);
    thread_exists(subthread_tid);

    pthread_cancel(subthread_tid);
    printf("pthread_cancel()\n");
    sleep(1);
    thread_exists(subthread_tid);

    error_number = pthread_join(subthread_tid, NULL);
    if( error_number == 0 ) {
        printf("pthread_join() successful\n");
    } else {
        printf("pthread_join() failed, %d\n", error_number);
    }
    thread_exists(subthread_tid);

    exit(0);
}
0
Eric Buell

巨大な隠れた欠陥を持っている「勝利」の答えに注意しましょう。いくつかのコンテキストでは、クラッシュにつながる可能性があります。 pthread_joinを使用しない限り、何度も起動します。プロセスと共有ライブラリがあるとします。ライブラリlib.soを呼び出します。

  1. それをdlopenし、その中でスレッドを開始します。あなたがそれに参加したくないので、それを取り外し可能に設定すると仮定します。
  2. 作業を行うなど、処理および共有ライブラリのロジックなど...
  3. Lib.soをロードする必要があります。これはもう必要ないからです。
  4. スレッドでシャットダウンを呼び出し、lib.soのスレッドからフラグを読み取り、終了したことを伝えます。
  5. Dlcloseを使用して別のスレッドを続行します。これは、フラグがスレッドを「終了」として表示していることを確認したためです。
  6. dlcloseは、すべてのスタックとコード関連のメモリをロードします。
  7. おっと、しかしdlcloseはスレッドを停止しません。クリーンアップハンドラーの最後の行にいて、「スレッドが終了した」揮発性アトミックフラグ変数を設定している場合でも、スタック上の多くのメソッドから戻って値を返すなどする必要があります。 #5 +#6のスレッドに巨大なスレッド優先順位が与えられた場合、スレッドで本当に停止する前にdlcloseを受け取ります。時々、ニースのクラッシュが発生します。

これは仮説的な問題ではないことを指摘させてください。私たちのプロジェクトでも同じ問題がありました。

0
newhouse