フォークとクローンに関して混乱があります。私はそれを見てきました:
forkはプロセス用で、cloneはスレッド用です
forkは単にcloneを呼び出し、cloneはすべてのプロセスとスレッドに使用されます
これらのどちらかが正確ですか?2.6 Linuxカーネルでのこれら2つのシステムコールの違いは何ですか?
フォークとクローンに関して混乱があります。私はそれを見てきました:
forkはプロセス用で、cloneはスレッド用です
forkは単にcloneを呼び出し、cloneはすべてのプロセスとスレッドに使用されます
これらのどちらかが正確ですか?2.6 Linuxカーネルでのこれら2つのシステムコールの違いは何ですか?
回答:
fork()
元のUNIXシステムコールでした。スレッドではなく、新しいプロセスの作成にのみ使用できます。また、ポータブルです。
Linuxではclone()
、新しい実行スレッドを作成するために使用できる、新しい多用途のシステムコールです。渡されたオプションに応じて、新しい実行スレッドは、UNIXプロセスのセマンティクス、POSIXスレッド、間にあるもの、または完全に異なるもの(異なるコンテナーなど)に準拠できます。メモリ、ファイル記述子、さまざまなネームスペース、シグナルハンドラなどを共有するかコピーするかを指定するあらゆる種類のオプションを指定できます。
以来clone()
スーパーセットのシステムコールである、の実装fork()
のglibcでのシステムコールのラッパーは実際に呼び出しますclone()
が、これはプログラマが知っている必要はありませんことを、実装の詳細です。fork()
非常に古いバージョンのlibc、またはglibc以外の別のlibcを使用するプログラムが使用する可能性があるため、実際の実際のシステムコールは、冗長になりましたが、下位互換性の理由でLinuxカーネルに存在します。
clone()
また、pthread_create()
スレッドを作成するためのPOSIX関数の実装にも使用されます。
ポータブルのプログラムが呼び出す必要がありますfork()
とpthread_create()
、ありませんclone()
。
clone()
Linux 2.6には2つのことが浮かんでいるように見えます
システムコールがあります:
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
これは、を行うことによって記述される「clone()」man 2 clone
です。
そのマニュアルページを十分に近く読んだ場合、これが表示されます:
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
システムコールを行い、実際にフォークかを確認します。strace
Linux 2.6.18マシン(x86_64 CPU)でこれを取得しました:
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)
strace
出力に「fork」呼び出しは表示されません。clone()
でコールショーアップstrace
出力がman-ページ-クローンからの非常に異なる引数を持っています。child_stack=0
最初の引数がと異なるためint (*fn)(void *)
。
「ライブラリ関数」が実装されているように、fork(2)
システムコールは実数 clone()
でclone()
実装されているようです。本当のは clone()
、マンページ-クローンからの引数の異なるセットを持っています。
単純に言えば、あなたの見かけ上矛盾している、fork()
そしてclone()
正しい両方の声明の両方。ただし、関与する「クローン」は異なります。
man 2 clone
まさにそのように表現しているだけで、問題を混乱させ、質問者が良い答えを得るのを妨げていると私は思った。
clone
基盤となるシステムコールが受け付ける引数リストから、実質的にライブラリの機能が異なります。具体的には、システムコールfork
は、従来の方法と同じように、常に同じスタックで2回返されます。子スタックに関連するすべての引数は、ユーザー空間で厳密に処理されます。たとえば、sourceware.org
fork()
はシステムコールに対するフラグの特定のセットですclone()
。clone()
「プロセス」または「スレッド」、あるいはプロセスとスレッドの間のどこかにある奇妙なもの(たとえば、同じファイル記述子テーブルを共有する異なる「プロセス」)を作成するのに十分です。
基本的に、カーネル内の実行コンテキストに関連付けられた情報の「タイプ」ごとに、clone()
その情報をエイリアス化するかコピーするかを選択できます。スレッドはエイリアスに対応し、プロセスはコピーに対応します。フラグの中間の組み合わせをに指定することによりclone()
、スレッドでもプロセスでもない奇妙なものを作成できます。通常はこれを行うべきではありません。Linuxカーネルの開発中に、などの一般的なメカニズムを許可すべきかどうかについて議論があったと思いclone()
ます。