2.6カーネルLinuxでのフォークとクローン


37

フォークとクローンに関して混乱があります。私はそれを見てきました:

  • forkはプロセス用で、cloneはスレッド用です

  • forkは単にcloneを呼び出し、cloneはすべてのプロセスとスレッドに使用されます

これらのどちらかが正確ですか?2.6 Linuxカーネルでのこれら2つのシステムコールの違いは何ですか?

回答:


52

fork()元のUNIXシステムコールでした。スレッドではなく、新しいプロセスの作成にのみ使用できます。また、ポータブルです。

Linuxではclone()、新しい実行スレッドを作成するために使用できる、新しい多用途のシステムコールです。渡されたオプションに応じて、新しい実行スレッドは、UNIXプロセスのセマンティクス、POSIXスレッド、間にあるもの、または完全に異なるもの(異なるコンテナーなど)に準拠できます。メモリ、ファイル記述子、さまざまなネームスペース、シグナルハンドラなどを共有するかコピーするかを指定するあらゆる種類のオプションを指定できます。

以来clone()スーパーセットのシステムコールである、の実装fork()のglibcでのシステムコールのラッパーは実際に呼び出しますclone()が、これはプログラマが知っている必要はありませんことを、実装の詳細です。fork()非常に古いバージョンのlibc、またはglibc以外の別のlibcを使用するプログラムが使用する可能性があるため、実際の実際のシステムコールは、冗長になりましたが、下位互換性の理由でLinuxカーネルに存在します。

clone()また、pthread_create()スレッドを作成するためのPOSIX関数の実装にも使用されます。

ポータブルのプログラムが呼び出す必要がありますfork()pthread_create()、ありませんclone()


2
posix_spawnは別の関連する関数です-いくつかの点でforkよりも移植性があります。
Random832

10

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システムコールを行い、実際にフォークかを確認します。straceLinux 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()正しい両方の声明の両方。ただし、関与する「クローン」は異なります。


9
「実際には、基になるclone()システムコールの上に階層化されたライブラリ関数です。」—一般に、これはすべてのシステムコールに適用されます。プログラマは、実際には常にシステムコールにちなんで名付けられたlibcの関数を呼び出します。これは、Cから直接実際の実際のシステムコールを行うには、プラットフォーム固有のマジック(通常、何らかの種類のCPUトラップを強制することにより、アーキテクチャABIに依存する)とマシンコードがlibcに委任されるのが最善だからです。
セラダ

1
@セラダ-はい、同意しました。それはman 2 cloneまさにそのように表現しているだけで、問題を混乱させ、質問者が良い答えを得るのを妨げていると私は思った。
ブルースエディガー

2
私は、マンページ手段を示すために信じている引数リストclone基盤となるシステムコールが受け付ける引数リストから、実質的にライブラリの機能が異なります。具体的には、システムコールforkは、従来の方法と同じように、常に同じスタックで2回返されます。子スタックに関連するすべての引数は、ユーザー空間で厳密に処理されます。たとえば、sourceware.org
git

1
私はあなたの答えを最高の答えにしたかったのです。なぜなら、それは揺れるからです。しかし、私は群れに左右され、最初の答えを選びました。彼女は応答時間のポイントを取得します。ご説明ありがとうございます。
グレッグレベンタール

6

fork()はシステムコールに対するフラグの特定のセットですclone()clone()「プロセス」または「スレッド」、あるいはプロセスとスレッドの間のどこかにある奇妙なもの(たとえば、同じファイル記述子テーブルを共有する異なる「プロセス」)を作成するのに十分です。

基本的に、カーネル内の実行コンテキストに関連付けられた情報の「タイプ」ごとに、clone()その情報をエイリアス化するかコピーするかを選択できます。スレッドはエイリアスに対応し、プロセスはコピーに対応します。フラグの中間の組み合わせをに指定することによりclone()、スレッドでもプロセスでもない奇妙なものを作成できます。通常はこれを行うべきではありません。Linuxカーネルの開発中に、などの一般的なメカニズムを許可すべきかどうかについて議論があったと思いclone()ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.