私はpthreadが初めてであり、それを理解しようとしています。次のような例をいくつか見ました。
main()
がAPI pthread_exit()
によってブロックされていることがわかりました。また、API pthread_join()
によってメイン関数がブロックされている例を見ました。何をいつ使うべきか理解できませんか?
私は次のサイトを参照しています- https://computing.llnl.gov/tutorials/pthreads/ 。 pthread_join()
をいつ使用するか、pthread_exit()
をいつ使用するかという概念が得られません。
誰か説明してもらえますか?また、pthreadに関する優れたチュートリアルリンクも歓迎します。
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
もう1つ、つまり.
pthread_cancel(thread);
pthread_join(thread, NULL);
実行中にスレッドをキャンセルしたい場合があります。これは、pthread_cancel(thread);を使用して実行できます。ただし、pthreadキャンセルサポートを有効にする必要があることに注意してください。また、キャンセル時にコードをクリーンアップします。
thread_cleanup_Push(my_thread_cleanup_handler, resources);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
static void my_thread_cleanup_handler(void *arg)
{
// free
// close, fclose
}
Openpubのドキュメントで説明されているように、
pthread_exit()
は、呼び出し元のスレッドを終了します。
あなたの場合、メインはそれを呼び出すので、メインthreadは終了しますが、生成されたスレッドは実行を続けます。これは主に、メインスレッドがスレッドを生成し、スレッドに任せるためだけに必要な場合に使用されます。
pthread_join
は、ターゲットスレッドが終了しない限り、それを呼び出したスレッドの実行を中断します。
これは、メインスレッドでさらに処理する前にスレッドが終了するのを待ちたい場合に役立ちます。
pthread_exit
は呼び出しスレッドを終了しますが、pthread_join
は、ターゲットスレッドの実行が完了するまで、呼び出しスレッドの実行を中断します。
これらは、公開グループのドキュメントで詳細に説明されています。
どちらの方法でも、すべてのスレッドが終了する前にprocessが終了しないようにします。
結合メソッドには、main
関数のスレッドが、「結合」されるすべてのスレッドを明示的に待機させます。
pthread_exit
メソッドは、main
関数とスレッドを制御された方法で終了します。 main
には、他のすべてのスレッドを含むプロセス全体を終了するmain
が終了するという特殊性があります。
これが機能するためには、main
関数内で宣言されているローカル変数をスレッドが使用していないことを確認する必要があります。この方法の利点は、main
がプロセスで開始されたすべてのスレッドを知る必要がないことです。たとえば、他のスレッドがmain
が知らない新しいスレッドを作成したためです。何でも。
既に述べたように、呼び出しスレッドの終了に使用されます。その関数を呼び出すと、複雑なクリーンアップメカニズムが開始されます。完了すると、スレッドは終了します。 pthread_exit()APIは、pthread_create()によって作成されたスレッドでreturn()ルーチンの呼び出しが発生した場合にも暗黙的に呼び出されます。実際には、return()の呼び出しとpthread_exit()の呼び出しは、pthread_create()によって作成されたスレッドから呼び出されるのと同じ影響を及ぼします。
Main()関数の開始時に暗黙的に作成される初期スレッドと、pthread_create()によって作成されるスレッドを区別することは非常に重要です。 main()関数からreturn()ルーチンを呼び出すと、暗黙的にexit()システムコールが呼び出され、プロセス全体が終了します。スレッドクリーンアップメカニズムは開始されません。 main()関数からpthread_exit()を呼び出すと、クリーンアップメカニズムが開始され、作業が完了すると初期スレッドが終了します。
Main()関数からpthread_exit()が呼び出されたときにプロセス全体(および他のスレッド)に何が起こるかは、PTHREAD実装に依存します。たとえば、IBM OS/400実装では、pthread_exit()がmain()関数から呼び出されると、他のスレッドを含むプロセス全体が終了します。他のシステムの動作は異なる場合があります。ほとんどの最新のLinuxマシンでは、初期スレッドからpthread_exit()を呼び出しても、すべてのスレッドが終了するまでプロセス全体が終了しません。 移植可能なアプリケーションを作成する場合は、main()からpthread_exit()を使用する際に注意してください。
スレッドの終了を待つ便利な方法です。 pthread_join()を使用する代わりに、おそらくアプリケーションに適した、スレッドの終了を待つ独自の関数を作成できます。たとえば、条件変数の待機に基づく関数にすることができます。
David R. Butenhof“ Programming with POSIX Threads”。の本を読むことをお勧めします。主な機能、常に本に反映されているわけではありません)。
特定のコードで pthread_exit(3)
を呼び出す必要はありません。
一般に、main
スレッドはnot_pthread_exit
_を呼び出す必要がありますが、多くの場合 pthread_join(3)
を呼び出す必要がありますtowait他のスレッドが終了するまで。
PrintHello
関数では、_pthread_exit
_を呼び出す必要はありません。これは、関数から戻った後は暗黙的であるためです。
したがって、コードは次のようになります。
_void *PrintHello(void *threadid) {
long tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
return threadid;
}
int main (int argc, char *argv[]) {
pthread_t threads[NUM_THREADS];
int rc;
intptr_t t;
// create all the threads
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", (long) t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc) { fprintf(stderr, "failed to create thread #%ld - %s\n",
(long)t, strerror(rc));
exit(EXIT_FAILURE);
};
}
pthread_yield(); // useful to give other threads more chance to run
// join all the threads
for(t=0; t<NUM_THREADS; t++){
printf("In main: joining thread #%ld\n", (long) t);
rc = pthread_join(&threads[t], NULL);
if (rc) { fprintf(stderr, "failed to join thread #%ld - %s\n",
(long)t, strerror(rc));
exit(EXIT_FAILURE);
}
}
}
_
pthread_exit()
は、呼び出しスレッドを終了して終了します(ただし、呼び出しスレッドが使用するリソースは、メインスレッドから切り離されていない場合、オペレーティングシステムに解放されません。)
pthrade_join()
は、ターゲットスレッドが終了しないまで、呼び出しスレッドを待機またはブロックします。単純なWordでは、ターゲットスレッドを終了するまで待機します。
コードで、PrintHello
関数のpthread_exit()
の前にsleep(またはdelay)を入れると、メインスレッドが終了し、完全なプロセスを終了する場合がありますが、PrintHello
関数は完了していない場合、終了します。 mainからpthrade_join()
を呼び出す前にmainでpthread_exit()
関数を使用すると、メインスレッドがブロックされ、呼び出しスレッド(PrintHello
)が完了するまで待機します。
うーん。
POSIX pthread_exit
の説明 http://pubs.opengroup.org/onlinepubs/009604599/functions/pthread_exit.html :
After a thread has terminated, the result of access to local (auto) variables of the thread is
undefined. Thus, references to local variables of the exiting thread should not be used for
the pthread_exit() value_ptr parameter value.
これは、ローカルのmain()スレッド変数は引き続きアクセス可能であるという考えに反しているようです。
メインスレッドで(pthread_exit
の代わりに)pthread_join
を使用すると、メインスレッドは無効(ゾンビ)状態のままになります。 pthread_join
を使用しないため、終了した他の結合可能なスレッドもゾンビ状態のままになり、リソースリークが発生します。
結合可能なスレッド(つまり、切り離されていないスレッド)との結合に失敗すると、「ゾンビスレッド」が生成されます。各ゾンビスレッドはいくつかのシステムリソースを消費し、十分なゾンビスレッドが蓄積されると、新しいスレッド(またはプロセス)を作成できなくなるため、これを避けてください。
別のポイントは、メインスレッドを無効な状態に保つことです。一方、他のスレッドの実行中は、リソースがメインスレッドに割り当てられている場合や、メインスレッドに対してローカルな変数が他のスレッドで使用されている場合など、さまざまな条件で実装依存の問題を引き起こす可能性があります。
また、すべての共有リソースはプロセスが終了したときにのみ解放され、リソースは保存されません。したがって、pthread_exit
の代わりにpthread_join
を使用することは避けるべきだと思います。