2016-10-06 4 views
2

スレッドからfork() sys_callを呼び出すことは悪い考えです。 しかし、スレッドがfork()を使用して新しいプロセスを作成するとどうなりますか?スレッドがフォークするとどうなりますか?

新しいプロセスは、スレッドを作成したメインスレッドの子になります。おもう。

親が最初に終了した場合、新しいプロセスがinitプロセスにアタッチされます。 その親はメインスレッドであり、それを作成したスレッドではありません。

私が間違っている場合は私を修正してください。

#include <stdio.h> 
#include <pthread.h> 

int main() 
{ 
    thread_t pid; 
    pthread_create(&(pid), NULL, &(f),NULL); 
    pthread_join(tid, NULL); 
    return 0; 
} 

void* f() 
{ 
    int i; 
    i = fork(); 

    if (i < 0) { 
     // handle error 
    } else if (i == 0) // son process 
    { 
      // Do something; 
    } else { 
      // Do something; 
    } 
} 

答えて

10

新しいプロセスはスレッドを作成したメインスレッドの子になります。おもう。

forkは、新しいプロセスを作成します。プロセスの親は別のプロセスであり、スレッドではありません。したがって、新しいプロセスの親は古いプロセスです。

forkforkを呼び出す(スタックの)スレッドだけを複製するため、子プロセスは1つのスレッドしか持たないことに注意してください。 (メモリ全体が複製されますが、子プロセスにはアクティブなスレッドが1つしかありません)

親が最初に終了すると、新しいプロセスがinitプロセスにアタッチされます。

親が最初に終了した場合、SIGHUP信号が子に送信されます。子がSIGHUPの結果として終了しない場合、新しい親としてinitが得られます。 SIGHUPの詳細については、nohupおよびsignal(7)のマニュアルページも参照してください。

親はメインスレッドであり、それを作成したスレッドではありません。

プロセスの親は特定のスレッドではなくプロセスなので、メインスレッドまたは子スレッドが親であると言うのは意味がありません。プロセス全体が親です。

最終的な注意点:スレッドとフォークの混合は注意して行う必要があります。いくつかの落とし穴については、hereを参照してください。

+0

SIGHUBは、親がPOSIXごとの制御プロセスである場合にのみ送信されます。子プロセスがSIGHUBを受け取ることは稀です。 – usr

0

問題は、フォークの動作(2)自体に由来します。新しい 子プロセスがfork(2)で作成されるたびに、新しいプロセスは新しい というメモリアドレス空間を取得しますが、メモリ内のすべてが古い プロセスからコピーされます(コピーオンライトは100%ではありませんが、 は同じです)。

マルチスレッド環境でfork(2)を呼び出すと、呼び出しが というスレッドが新しいプロセスのメインスレッドになり、親プロセスで実行されたスレッドがすべて終了しました。そして、すべて は、fork(2)の呼び出しの直前にそのまま残されました。

ここで、fork(2)の呼び出しの前にこれらの他のスレッドがうまく仕事をしていて、数ミリ秒後には が死んだとします。これらの死んだスレッドが何かをしたのであれば、そのまま のままにすることはできませんでしたか?

例を挙げておきます。私たちのメインスレッド( がfork(2)を呼び出す予定)が眠っていて、他のたくさんのスレッドが喜んで仕事をしていたとしましょう。メモリの割り当て、書き込み、 からのコピー、ファイルへの書き込み、データベースへの書き込みなど。 彼らはおそらくmalloc(3)のようなものでメモリを割り当てていたでしょう。 さて、malloc(3)は内部的にmutexを使用して のスレッドセーフティを保証しています。そして、これがまさに問題です。

メインスレッドが というfork(2)と同じタイミングで、これらのスレッドのいずれかがmalloc(3)を使用していて、mutexのロックを 取得した場合はどうなりますか?新しい子プロセスでは、ロックはまだ保持されています。返されることのない 死んだスレッドによって保持されます。

新しい子プロセスは、malloc(3) を使用するのが安全かどうかわかりません。最悪の場合、mockoc(3)を呼び出して、 がロックを取得するまでブロックします。これは、 のスレッドがそれを返すことになっているために発生しません。これは単なるmalloc(3)です。 について考えてみましょう。他のすべての可能なmutexとデータベースドライバのロック、ファイル 、ライブラリ、ネットワークライブラリなどの処理について考えてみましょう。

この説明はlinkです。

3

しかし、スレッドがfork()を使用して新しいプロセスを作成するとどうなりますか?

新しいプロセスは呼び出し元スレッドのアドレス空間(プロセスのないアドレス空間全体を)コピーすることによって作成されます。一般的には悪い考えであると考えられます。なぜなら、それを正しくするのは非常に難しいからです。 POSIXは、(マルチスレッドプログラムで作成された)子プロセスは、exec*関数の1つを呼び出すまで、async-signal-safe関数のみを呼び出すことができると述べています。

親が最初に終了した場合、新しいプロセスがinit プロセスにアタッチされます。

通常、子プロセスはinitプロセスによって継承されます。親プロセスが制御処理(例えばシェル)である場合には、POSIX requires:プロセスが制御プロセスの場合

、SIGHUP信号が のフォアグラウンドプロセスグループの各プロセスに を送らなければなりません呼び出し元プロセスに属する制御端末。

しかし、ほとんどのプロセスはプロセスを制御していないため、ほとんどのプロセスでは当てはまりません。

親はメインスレッドであり、それを作成したスレッドではありません。

フォークされた子の親は、常にfork()を呼び出したプロセスです。したがって、PPIDは子プロセスであり、あなたのプログラムのPIDになります。

+0

"呼び出し元のスレッドのアドレス空間をコピーする":プロセス内のスレッドは同じアドレス空間を共有するため、fork()はプロセスのアドレス空間全体をコピーします。 async-signal-safe関数に関する部分も間違っています。これはvfork()のみであり、full fork()ではありません。 – Arnout

+0

@Arnout POSIXの根拠はあなたの主張に同意しない。 http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_atfork.htmlを参照してください。「マルチスレッドプログラムでfork()のセマンティクスに少なくとも2つの深刻な問題があります。[...] fork()を使用するプログラムは、子プロセスですぐ後でexec関数を呼び出し、すべての状態をリセットすることをお勧めします。一方、非同期シグナル安全ライブラリルーチンの短いリストだけが利用可能であると約束しています。実際、ここでは全体の根拠が重要です。 – usr

関連する問題