web-dev-qa-db-ja.com

Linuxでpthread_exit()を使用するタイミングとpthread_join()を使用するタイミング

私は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
}
39

Openpubのドキュメントで説明されているように、

pthread_exit() は、呼び出し元のスレッドを終了します。

あなたの場合、メインはそれを呼び出すので、メインthreadは終了しますが、生成されたスレッドは実行を続けます。これは主に、メインスレッドがスレッドを生成し、スレッドに任せるためだけに必要な場合に使用されます。

pthread_join は、ターゲットスレッドが終了しない限り、それを呼び出したスレッドの実行を中断します。

これは、メインスレッドでさらに処理する前にスレッドが終了するのを待ちたい場合に役立ちます。

39

pthread_exitは呼び出しスレッドを終了しますが、pthread_joinは、ターゲットスレッドの実行が完了するまで、呼び出しスレッドの実行を中断します。

これらは、公開グループのドキュメントで詳細に説明されています。

13
Alok Save

どちらの方法でも、すべてのスレッドが終了する前にprocessが終了しないようにします。

結合メソッドには、main関数のスレッドが、「結合」されるすべてのスレッドを明示的に待機させます。

pthread_exitメソッドは、main関数とスレッドを制御された方法で終了します。 mainには、他のすべてのスレッドを含むプロセス全体を終了するmainが終了するという特殊性があります。

これが機能するためには、main関数内で宣言されているローカル変数をスレッドが使用していないことを確認する必要があります。この方法の利点は、mainがプロセスで開始されたすべてのスレッドを知る必要がないことです。たとえば、他のスレッドがmainが知らない新しいスレッドを作成したためです。何でも。

8
Jens Gustedt

Pthread_exit()API

既に述べたように、呼び出しスレッドの終了に使用されます。その関数を呼び出すと、複雑なクリーンアップメカニズムが開始されます。完了すると、スレッドは終了します。 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()API

スレッドの終了を待つ便利な方法です。 pthread_join()を使用する代わりに、おそらくアプリケーションに適した、スレッドの終了を待つ独自の関数を作成できます。たとえば、条件変数の待機に基づく関数にすることができます。

David R. Butenhof“ Programming with POSIX Threads”。の本を読むことをお勧めします。主な機能、常に本に反映されているわけではありません)。

2
MichaelGoren

特定のコードで 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)が完了するまで待機します。

2
Abhitesh khatri

うーん。

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()スレッド変数は引き続きアクセス可能であるという考えに反しているようです。

1
jim mcnamara

メインスレッドで(pthread_exitの代わりに)pthread_joinを使用すると、メインスレッドは無効(ゾンビ)状態のままになります。 pthread_joinを使用しないため、終了した他の結合可能なスレッドもゾンビ状態のままになり、リソースリークが発生します。

結合可能なスレッド(つまり、切り離されていないスレッド)との結合に失敗すると、「ゾンビスレッド」が生成されます。各ゾンビスレッドはいくつかのシステムリソースを消費し、十分なゾンビスレッドが蓄積されると、新しいスレッド(またはプロセス)を作成できなくなるため、これを避けてください。

別のポイントは、メインスレッドを無効な状態に保つことです。一方、他のスレッドの実行中は、リソースがメインスレッドに割り当てられている場合や、メインスレッドに対してローカルな変数が他のスレッドで使用されている場合など、さまざまな条件で実装依存の問題を引き起こす可能性があります。

また、すべての共有リソースはプロセスが終了したときにのみ解放され、リソースは保存されません。したがって、pthread_exitの代わりにpthread_joinを使用することは避けるべきだと思います。

0
Preeti