私のデストラクタでは、スレッドをきれいに破壊したいです。
私の目標は、スレッドの実行が完了するのを待ってから、スレッドを破棄することです。
Pthreadの状態を照会することに関して私が見つけた唯一のことは pthread_attr_setdetachstate ですが、これはあなたのスレッドが次の場合にのみ教えてくれます:
どちらも、スレッドがまだ実行中かどうかとは関係ありません。
pthreadを照会して、まだ実行中かどうかを確認するにはどうすればよいですか?
ここには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つのスレッドが同じデータに一貫してアクセスできます同期コンストラクト(ミューテックス/セマフォ)は必要ありません。
pthread_kill(tid, 0);
シグナルは送信されませんが、エラーチェックが実行されるため、それを使用してtidの存在を確認できます。
[〜#〜] caution [〜#〜]:この答えは間違っています。この規格では、ライフタイムが終了したスレッドのIDを渡すことを特に禁止しています。そのIDは現在、別のスレッドを指定している可能性があり、さらに悪いことに、解放されたメモリを参照してクラッシュを引き起こしている可能性があります。
本当に必要なのはpthread_join()を呼び出すことだけだと思います。その呼び出しは、スレッドが終了するまで戻りません。
スレッドがまだ実行されているかどうかを確認するためだけにポーリングしたい場合(そして、通常はあなたがしたいことではないことに注意してください!)、終了する直前にスレッドにvolatileブール値をfalseに設定させることができます。メインスレッドはブール値を読み取ることができ、それでもtrueであれば、スレッドがまだ実行されていることがわかります。 (一方、falseの場合、スレッドは少なくともほとんどなくなっていることがわかります。ブール値をfalseに設定した後に発生するクリーンアップコードを実行している可能性がありますので、この場合でも前にpthread_joinを呼び出す必要がありますスレッドがアクセスできる可能性のあるリソースを解放しようとしています)
完全に移植可能なソリューションはありません。プラットフォームがpthread_tryjoin_npまたはpthread_timedjoin_npをサポートしているかどうかを確認してください。したがって、スレッドを結合できるかどうかを確認するだけです(もちろん、PTHREAD_CREATE_JOINABLEで作成されます)。
少なくとも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);
}
巨大な隠れた欠陥を持っている「勝利」の答えに注意しましょう。いくつかのコンテキストでは、クラッシュにつながる可能性があります。 pthread_joinを使用しない限り、何度も起動します。プロセスと共有ライブラリがあるとします。ライブラリlib.soを呼び出します。
これは仮説的な問題ではないことを指摘させてください。私たちのプロジェクトでも同じ問題がありました。