【C言語】 スレッドの終了処理をもっとスマートに! `thrd_exit` 関数とその他の方法を比較
thrd_exit
関数の詳細
thrd_exit
関数は、以下の引数を受け取ります。
res
: スレッドの終了ステータスを表す整数値
この関数は、以下の処理を行います。
- スレッド固有ストレージの解放: スレッド固有ストレージ (TSS) に登録されたすべてのキーについて、関連付けられたデストラクタを呼び出し、値を NULL に設定します。
- スレッドの終了: スレッドの実行を停止し、システムリソースを解放します。
- 終了ステータスの設定: 終了ステータス
res
をスレッドに設定します。
thrd_exit
関数の使用例
#include <threads.h>
void *thread_function(void *arg) {
// スレッド内の処理
thrd_exit(0); // 正常終了
}
int main() {
thrd_t tid;
thrd_create(&tid, thread_function, NULL);
thrd_join(tid, NULL);
return 0;
}
この例では、thread_function
というスレッド関数が作成され、その中で thrd_exit(0)
を呼び出して正常に終了しています。
- スレッドが終了する前に、適切な後処理を行う必要があります。
thrd_exit
関数は、呼び出し側スレッドのみを終了させます。他のスレッドの影響には及びません。
スレッド内の処理完了後に終了する例
#include <threads.h>
void *thread_function(void *arg) {
// スレッド内の処理
// 処理完了後に終了
thrd_exit(0);
}
int main() {
thrd_t tid;
thrd_create(&tid, thread_function, NULL);
thrd_join(tid, NULL);
return 0;
}
終了ステータスを設定して終了する例
#include <threads.h>
void *thread_function(void *arg) {
// スレッド内の処理
// 終了ステータスを設定
thrd_exit(1); // エラー終了
}
int main() {
thrd_t tid;
int status;
thrd_create(&tid, thread_function, NULL);
thrd_join(tid, &status);
if (status == 0) {
printf("スレッドは正常に終了しました\n");
} else {
printf("スレッドはエラーで終了しました\n");
}
return 0;
}
この例では、thread_function
というスレッド関数が作成され、その中で処理を実行した後、thrd_exit(1)
を呼び出してエラー終了しています。main
関数では、thrd_join
関数を使用してスレッドの終了ステータスを取得し、正常終了かエラー終了かを判断しています。
スレッド固有ストレージのデストラクタを呼び出す例
#include <threads.h>
typedef struct {
int value;
thrd_destructor_t destructor;
} thread_data_t;
void destructor(void *arg) {
thread_data_t *data = (thread_data_t *)arg;
printf("スレッド固有ストレージの値: %d\n", data->value);
free(data);
}
void *thread_function(void *arg) {
thread_data_t *data = (thread_data_t *)arg;
// スレッド内の処理
// スレッド固有ストレージの解放
thrd_exit(0);
}
int main() {
thrd_t tid;
thread_data_t data = {10, destructor};
thrd_create(&tid, thread_function, &data);
thrd_join(tid, NULL);
return 0;
}
この例では、thread_data_t
という構造体を定義し、value
フィールドと destructor
フィールドをメンバ変数として持たせています。destructor
フィールドは、スレッド固有ストレージの解放時に呼び出されるデストラクタ関数へのポインタを格納します。
thread_function
関数では、thread_data_t
構造体のインスタンスをスレッド固有ストレージに登録し、処理を実行した後、thrd_exit(0)
を呼び出して終了します。
main
関数では、thread_data_t
構造体のインスタンスを作成し、thrd_create
関数を使用してスレッドを作成します。その後、thrd_join
関数を使用してスレッドの終了を待機します。
スレッドの終了を待つ例
#include <threads.h>
void *thread_function(void *arg) {
// スレッド内の処理
// 終了処理
thrd_exit(0);
}
int main() {
thrd_t tid;
thrd_create(&tid, thread_function, NULL);
// スレッドの終了を待つ
thrd_join(tid, NULL);
return 0;
}
この例では、thread_function
というスレッド関数が作成され、その中で処理を実行した後、thrd_exit(0)
を呼び出して終了しています。main
関数では、thrd_join
関数を使用してスレッドの終了を待機しています。
pthread_exit 関数
pthread_exit
関数は、POSIX Threads 以外のスレッドライブラリで使用される関数であり、thrd_exit
関数と同様の機能を提供します。使用するスレッドライブラリに応じて、適切な関数を選択する必要があります。
#include <pthread.h>
void *thread_function(void *arg) {
// スレッド内の処理
// 終了処理
pthread_exit(0); // 正常終了
}
return 文
return
文は、関数から制御を返すために使用されますが、スレッド関数においても return
文を使用することでスレッドを終了させることができます。
#include <pthread.h>
void *thread_function(void *arg) {
// スレッド内の処理
// 終了処理
return 0; // 正常終了
}
cancel() 関数
cancel()
関数は、別のスレッドから実行中のスレッドを強制終了するために使用されます。
#include <pthread.h>
void *thread_function(void *arg) {
// スレッド内の処理
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_function, NULL);
// スレッドを強制終了
pthread_cancel(tid);
pthread_join(tid, NULL);
return 0;
}
シグナル処理を使用してスレッドを終了させることもできます。
#include <pthread.h>
#include <signal.h>
void *thread_function(void *arg) {
// スレッド内の処理
// シグナルハンドラを設定
signal(SIGTERM, signal_handler);
// シグナルを待つ
pause();
}
void signal_handler(int sig) {
// 終了処理
pthread_exit(0);
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, thread_function, NULL);
// スレッドに SIGTERM シグナルを送信
pthread_kill(tid, SIGTERM);
pthread_join(tid, NULL);
return 0;
}
上記以外にも、スレッドを終了させる方法はいくつかあります。使用する方法は、状況や環境によって異なります。