27

同じプロセスのメインスレッドと他のスレッドに問題があります。main関数が戻ると、他のスレッドも終了しますか?私はこれについて混乱しています。

次のテストコードを検討してください。

void* test1(void *arg)
{
    unsigned int i = 0;
    while (1){
        i+=1;
    }
    return NULL;
}

void* test2(void *arg)
{
    long double i = 1.0;
    while (1){
        i *= 1.1;
    }
    return NULL;
}

void startThread ( void * (*run)(void*), void *arg) {
  pthread_t t;
  pthread_attr_t attr;
  if (pthread_attr_init(&attr) != 0
      || pthread_create(&t, &attr, run, arg) != 0
      || pthread_attr_destroy(&attr) != 0
      || pthread_detach(t) != 0) {
    printf("Unable to launch a thread\n");
    exit(1);
  }
}

int main()
{
    startThread(test1, NULL);
    startThread(test2, NULL);

    sleep(4);
    printf("main thread return.\n");

    return 0;
}

「メインスレッド復帰」時。印刷し、スレッドtest1とtest2も終了します。理由を教えてもらえますか?

4

3 に答える 3

29

新しいスレッドのそれぞれでを使用pthread_join()して、呼び出し元のスレッドにサブスレッドを待機するように通知し、それらのスレッドが終了するまで実行を一時停止し、プロセスを終了する必要があります。

pthread_detach作成されたスレッドを呼び出すと、プロセスが終了した後もスレッドが保持されません。linuxのmanページから:

detached属性は、スレッドが終了したときのシステムの動作を決定するだけです。プロセスがexit(3)を使用して終了した場合(または同等に、メインスレッドが戻った場合)、スレッドの終了を妨げることはありません。

明示的な呼び出しの代わりにpthread_exitinが使用されている場合があります。この方法で終了すると、他のスレッドが実行を継続できるようになります。実際、linuxのマニュアルページにはこれが明示的に記載されています。mainpthread_joinmain

他のスレッドが実行を継続できるようにするには、メインスレッドはexit(3)ではなくpthread_exit()を呼び出して終了する必要があります。

しかし、これがすべてのプラットフォームで期待される動作であるかどうかはわかりません。私は常にを使用し続けていpthread_joinます。

pthread_joinターゲットスレッドにはが必要です。したがって、両方を待機するためpthread_tに呼び出す前に両方のスレッドを作成する必要があるため、コードを少し変更する必要があります。pthread_joinしたがって、で呼び出すことはできませんstartThread。を返すか、関数へpthread_tのポインタを渡す必要があります。pthread_tstartThread

于 2012-08-09T02:31:21.813 に答える
24

メインスレッドが戻ると(つまり、main関数から戻ると)、プロセス全体が終了します。これには、他のすべてのスレッドが含まれます。を呼び出すときにも同じことが起こりますexit。を呼び出すことでこれを回避できますpthread_exit

の目的はpthread_detach、リソースを解放するために他のスレッドに参加する必要がないようにすることです。スレッドを切り離しても、プロセスの終了を過ぎても存在するわけではなく、他のすべてのスレッドと一緒に破棄されます。

于 2012-08-09T02:41:00.810 に答える
1

から戻ると、プロセス内のすべてのスレッドが終了しますmain()

ライブラリは、関数が戻ったときにlibc呼び出すことによってこの動作を実装する責任があります。次に、この関数は、 (v2.3以降で)最終的に exit_groupシステムコールを呼び出してプロセスを終了し、そのすべてのスレッドを終了するという名前のシンラッパー関数を呼び出すことになります。exit()main()exit()_exit()libc

この最後のシステムコールは、気付いた動作の原因です。

この微妙なメモは、こちら_exit()のマニュアルで確認できます。

C library/kernel differences
       In glibc up to version 2.3, the _exit() wrapper function invoked
       the kernel system call of the same name.  Since glibc 2.3, the
       wrapper function invokes exit_group(2), in order to terminate all
       of the threads in a process.

この動作を回避することが目的の場合、唯一のオプションは、メインスレッドを終了し、の関数pthread_exitに戻れないようにする呼び出しです。libc__libc_start_main()

于 2021-07-15T16:09:10.950 に答える