フォークとクローンに関して混乱しています。私はそれを見ました:
forkはプロセス用で、cloneはスレッド用です
forkはcloneを呼び出すだけで、cloneはすべてのプロセスとスレッドに使用されます
これらのいずれかは正確ですか? 2.6 Linuxカーネルでのこれら2つのシステムコールの違いは何ですか?
fork()
は、元のUNIXシステムコールでした。スレッドではなく、新しいプロセスの作成にのみ使用できます。また、ポータブルです。
Linuxでは、clone()
は新しい多目的システムコールであり、新しい実行スレッドを作成するために使用できます。渡されたオプションに応じて、新しい実行スレッドは、UNIXプロセスのセマンティクス、POSIXスレッド、その中間、またはまったく異なるもの(異なるコンテナーのような)に準拠できます。メモリ、ファイル記述子、さまざまな名前空間、シグナルハンドラーなどを共有するかコピーするかを指定するあらゆる種類のオプションを指定できます。
clone()
はスーパーセットシステムコールであるため、glibcのfork()
システムコールラッパーの実装は実際にclone()
を呼び出しますが、これはプログラマーが行わない実装の詳細ですtについて知る必要があります。非常に古いバージョンのlibc、またはglibc以外の別のlibcを使用するプログラムがそれを使用する可能性があるため、実際のfork()
システムコールは、下位互換性のためにLinuxカーネルにまだ存在しています。
clone()
は、スレッドを作成するためのpthread_create()
POSIX関数の実装にも使用されます。
移植可能なプログラムは、fork()
ではなくpthread_create()
およびclone()
を呼び出す必要があります。
Linux 2.6には、2つのclone()
が浮かんでいるようです
システムコールがあります:
_int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
_
これは、_man 2 clone
_を実行することによって記述される "clone()"です。
そのmanページを十分に読むと、次のようになります。
_It is actually a library function layered on top of the
underlying clone() system call.
_
どうやら、あなたは紛らわしく同じ名前のシステムコールに階層化された「ライブラリ関数」を使用してスレッドを実装することになっています。
私は短いプログラムを書いた:
_#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int
main(int ac, char **av)
{
pid_t cpid;
switch (cpid = fork()) {
case 0: // Child process
break;
case -1: // Error
break;
default: // parent process
break;
}
return 0;
}
_
_c99 -Wall -Wextra
_を使用してコンパイルし、_strace -f
_の下で実行して、システムフォークの実際の動作を確認します。私はこれをLinux 2.6.18マシン(x86_64 CPU)のstrace
から取り出しました:
_20097 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b4ee9213770) = 20098
20097 exit_group(0) = ?
20098 exit_group(0)
_
「fork」呼び出しはstrace
出力に表示されません。 strace
出力に表示されるclone()
呼び出しには、man-page-cloneとは非常に異なる引数があります。最初の引数がint (*fn)(void *)
と異なるため、_child_stack=0
_。
fork(2)
システムコールはrealclone()
の観点から実装されているようです。 "ライブラリ関数" clone()
は実装されました。 realclone()
には、man-page-cloneとは異なる引数のセットがあります。
単純に言えば、fork()
とclone()
に関する明らかに矛盾するステートメントはどちらも正しいです。ただし、含まれる「クローン」は異なります。
fork()
は、システムコールclone()
に対する特定のフラグセットです。 clone()
は、「プロセス」または「スレッド」、あるいはプロセスとスレッドの間にある奇妙なもの(たとえば、同じファイル記述子テーブルを共有する異なる「プロセス」)を作成するのに十分一般的です。
基本的に、カーネルの実行コンテキストに関連付けられているすべての「タイプ」の情報について、clone()
を使用すると、その情報にエイリアスを付けるか、コピーするかを選択できます。スレッドはエイリアスに対応し、プロセスはコピーに対応します。 clone()
にフラグの中間的な組み合わせを指定することで、スレッドやプロセスではない奇妙なものを作成できます。通常、これを行うべきではありません。Linuxカーネルの開発中に、clone()
などの一般的なメカニズムを許可するかどうかについて、いくつかの議論があったと思います。