forkとexecの違い


199

違いは何ですかforkとはexec


3
良い、フォーク、EXEC、および他のプロセス制御機能の詳細な概要はであるyolinux.com/TUTORIALS/ForkExecProcesses.html
ジョナサンFingland

9
@Justin、我々はSOになりたいので、質問をプログラムするために行く場所。
paxdiablo 2010年

4
@ Polaris878:ああ、それは今やります!:D
Janusz Lenar 2012年

そうfork基本的にクローニングされた:O
セバスチャンHojas

回答:


364

新しいプロセスを開始する非常にシンプルな方法を提供するという点で、UNIXの精神を使用しforkexec例示しています。

forkコールは、基本的に同じで、現在のプロセスの複製になり、ほぼすべての方法。すべてがコピーされるわけではありません(たとえば、一部の実装ではリソースの制限)が、できるだけ近いコピーを作成するという考えです。

新しいプロセス(子)は異なるプロセスID(PID)を取得し、古いプロセス(親)のPIDをその親PID(PPID)として持ちます。2つのプロセスはまったく同じコードを実行しているので、戻りコードによってどちらがどちらであるかがわかります。fork子は0を取得し、親は子のPIDを取得します。もちろん、これはすべて、fork呼び出しが機能することを前提としています。機能しない場合、子は作成されず、親はエラーコードを受け取ります。

execコールは、基本的には新しいプログラムで全体の現在のプロセスを交換する方法です。プログラムを現在のプロセス空間にロードし、エントリポイントから実行します。

だから、forkそしてexec多くの場合、現在のプロセスの子として実行する新しいプログラムを取得するために順番に使用されています。シェルは通常find、次のようなプログラムを実行しようとするたびにこれを行います-シェルがフォークし、子がfindプログラムをメモリにロードして、すべてのコマンドライン引数、標準I / Oなどを設定します。

ただし、これらを一緒に使用する必要はありません。たとえば、プログラムに親コードと子コードの両方が含まれている場合は、プログラムがing forkなしでそれ自体に完全に受け入れられexecます(実装には注意が必要です。実装ごとに制限がある場合があります)。これはfork、親がリッスンに戻っている間に特定の要求を処理するためにTCPポートと自分のコピーを単にリッスンするデーモンにかなり多く使用されています(まだ使用されています)。

同様に、彼らは完成している知っているとプログラムがちょうどする必要はありません別のプログラムを実行したいforkexecその後、wait子供のために。子をプロセススペースに直接ロードできます。

一部のUNIX実装には、forkコピーオンライトと呼ばれるものを使用する最適化があります。これはfork、プログラムがその空間の何かを変更しようとするまで、プロセス空間のコピーを遅らせるトリックです。これは、使用してそれらのプログラムのために有用でforkはないexec、彼らは全体のプロセス空間をコピーする必要がないという点で。

exec 次のように呼び出された場合fork(これがほとんどの場合に発生します)、プロセススペースへの書き込みが発生し、子プロセスにコピーされます。

全体の家族があることに注意してくださいexec呼び出しは(execlexecleexecveなど)が、exec文脈でここではそれらのいずれかを意味します。

次の図fork/execは、bashシェルを使用してlsコマンドでディレクトリを一覧表示する一般的な操作を示しています。

+--------+
| pid=7  |
| ppid=4 |
| bash   |
+--------+
    |
    | calls fork
    V
+--------+             +--------+
| pid=7  |    forks    | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash   |             | bash   |
+--------+             +--------+
    |                      |
    | waits for pid 22     | calls exec to run ls
    |                      V
    |                  +--------+
    |                  | pid=22 |
    |                  | ppid=7 |
    |                  | ls     |
    V                  +--------+
+--------+                 |
| pid=7  |                 | exits
| ppid=4 | <---------------+
| bash   |
+--------+
    |
    | continues
    V

52

fork()現在のプロセスを2つのプロセスに分割します。または、言い換えると、あなたの素敵な線形のプログラムは、突然、1つのコードを実行する2つの別々のプログラムになります。

 int pid = fork();

 if (pid == 0)
 {
     printf("I'm the child");
 }
 else
 {
     printf("I'm the parent, my child is %i", pid);
     // here we can kill the child, but that's not very parently of us
 }

これは一種のあなたの心を打つことができます。これで、2つのプロセスによって実行される、ほぼ同じ状態のコードが1つ作成されました。子プロセスは、fork()呼び出しを中断したところから開始することを含め、それを作成したプロセスのすべてのコードとメモリを継承します。唯一の違いは、fork()あなたが親であるか子供であるかを知らせるリターンコードです。親である場合、戻り値は子のIDです。

execexecターゲットの実行可能ファイルを使用してプロセスを実行するように指示するだけで、2つのプロセスが同じコードを実行したり、同じ状態を継承したりする必要はありません。@Steve Hawkinsが言うように、現在のプロセスでターゲット実行可能ファイルを実行したexec後に使用できますfork


6
条件もありますpid < 0し、fork()呼び出しが失敗した
ジョナサンFingland

3
それは私の心をまったく吹き飛ばしません:-)共有ライブラリまたはDLLが使用されているたびに、2つのプロセスによって実行される1つのコードが発生します。
paxdiablo 2009年

31

Marc Rochkindよる「Advanced Unix Programming」のいくつかの概念は、特にWindows モデルに慣れている人にとって、fork()/ のさまざまな役割を理解するのに役立ちました。exec()CreateProcess()

プログラムは、ディスク上の通常のファイルに保存された命令とデータの集まりです。(1.1.2プログラム、プロセス、およびスレッドから)

プログラムを実行するために、カーネルは最初に新しいプロセスを作成するように求められます。これは、プログラムが実行される環境です。(1.1.2プログラム、プロセス、スレッドからも)

プロセスとプログラムの違いを完全に理解しないと、execまたはforkシステムコールを理解することはできません。これらの用語が初めての場合は、戻ってセクション1.1.2を確認してください。ここで先に進む準備ができている場合は、違いを1文で要約します。プロセスは、実行時に取得される他の多くのリソースだけでなく、命令、ユーザーデータ、システムデータセグメントで構成される実行環境です。一方、プログラムは、プロセスの命令とユーザーデータセグメントを初期化するために使用される命令とデータを含むファイルです。(5.3 execシステムコールから)

プログラムとプロセスの違いを理解したら、の動作fork()exec()機能は次のように要約できます。

  • fork() 現在のプロセスの複製を作成します
  • exec() 現在のプロセスのプログラムを別のプログラムで置き換えます

(これは本質的に、paxdiabloのはるかに詳細な回答の簡略化された「ダミー用」バージョンです)


29

Forkは呼び出しプロセスのコピーを作成します。一般的に構造に従う ここに画像の説明を入力してください

int cpid = fork( );

if (cpid = = 0) 
{

  //child code

  exit(0);

}

//parent code

wait(cpid);

// end

(子プロセスtext(code)、data、stackは呼び出しプロセスと同じ)子プロセスはifブロックでコードを実行します。

EXECは、現在のプロセスを新しいプロセスのコード、データ、スタックに置き換えます。一般的に構造に従う ここに画像の説明を入力してください

int cpid = fork( );

if (cpid = = 0) 
{   
  //child code

  exec(foo);

  exit(0);    
}

//parent code

wait(cpid);

// end

(exec呼び出しunixカーネルが子プロセスのテキスト、データ、スタックをクリアし、fooプロセスに関連するテキスト/データで埋めた後)したがって、子プロセスは異なるコード(fooのコード{親と同じではない})になります。


1
それは質問とは少し関係がありませんが、上記のこのコードは、子プロセスが最初にコードを終了した場合に競合状態を引き起こしませんか?その場合、親プロセスは子が自分自身を終了するのを待って永遠にぶらぶらしますよね?
stdout 2018

7

これらは一緒に使用され、新しい子プロセスを作成します。最初に、呼び出しforkは現在のプロセス(子プロセス)のコピーを作成します。次に、exec子プロセス内から呼び出され、親プロセスのコピーを新しいプロセスに「置き換え」ます。

プロセスは次のようになります。

child = fork();  //Fork returns a PID for the parent process, or 0 for the child, or -1 for Fail

if (child < 0) {
    std::cout << "Failed to fork GUI process...Exiting" << std::endl;
    exit (-1);
} else if (child == 0) {       // This is the Child Process
    // Call one of the "exec" functions to create the child process
    execvp (argv[0], const_cast<char**>(argv));
} else {                       // This is the Parent Process
    //Continue executing parent process
}

2
7行目には、exec()関数が子プロセスを作成することが記載されています。これは、fork()がすでに子プロセスを作成し、exec()呼び出しが、作成したばかりの新しいプロセスのプログラムを置き換えるだけなので、本当にそうですか
cbinder

4

fork()は、現在のプロセスのコピーを作成し、fork()呼び出しの直後から新しい子で実行します。fork()関数の後は、fork()関数の戻り値を除いて、同じです。(詳細については、RTFM。)その後、2つのプロセスがさらに分岐し、共有ファイルハンドルを介した場合を除いて、一方が他方に干渉することはありません。

exec()は、現在のプロセスを新しいプロセスに置き換えます。現在の子プロセスを置き換えるのではなく、別の子プロセスを起動したい場合にexec()がfork()に続くことが多いことを除いて、fork()とは関係ありません。


3

主な違いfork()とはexec()、それであります

fork()システムコールは、現在実行中のプログラムのクローンを作成します。元のプログラムは、fork()関数呼び出しの次のコード行から実行を継続します。クローンも次のコード行で実行を開始します。http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/から取得した次のコードを見てください。

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
    printf("--beginning of program\n");
    int counter = 0;
    pid_t pid = fork();
    if (pid == 0)
    {
        // child process
        int i = 0;
        for (; i < 5; ++i)
        {
            printf("child process: counter=%d\n", ++counter);
        }
    }
    else if (pid > 0)
    {
        // parent process
        int j = 0;
        for (; j < 5; ++j)
        {
            printf("parent process: counter=%d\n", ++counter);
        }
    }
    else
    {
        // fork failed
        printf("fork() failed!\n");
        return 1;
    }
    printf("--end of program--\n");
    return 0;
}

このプログラムは、fork()INGの前に、カウンター変数を宣言し、ゼロに設定します。fork呼び出しの後、2つのプロセスが並行して実行され、どちらも独自のバージョンのカウンターをインクリメントします。各プロセスは完了するまで実行され、終了します。プロセスは並行して実行されるため、どちらが先に完了するかを知る方法がありません。このプログラムを実行すると、次に示すような結果が出力されますが、実行ごとに結果が異なる場合があります。

--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3
--end of program--
child process: counter=4
child process: counter=5
--end of program--

exec()システムコールのファミリは、プロセスの現在実行中のコードを別のコードに置き換えます。プロセスはPIDを保持しますが、新しいプログラムになります。たとえば、次のコードを考えます。

#include <stdio.h> 
#include <unistd.h> 
main() {
 char program[80],*args[3];
 int i; 
printf("Ready to exec()...\n"); 
strcpy(program,"date"); 
args[0]="date"; 
args[1]="-u"; 
args[2]=NULL; 
i=execvp(program,args); 
printf("i=%d ... did it work?\n",i); 
} 

このプログラムは、execvp()関数を呼び出して、そのコードを日付プログラムに置き換えます。コードがexec1.cという名前のファイルに格納されている場合、コードを実行すると次の出力が生成されます。

Ready to exec()... 
Tue Jul 15 20:17:53 UTC 2008 

プログラムは、「Ready to exec()」という行を出力します。。。‖execvp()関数を呼び出した後、そのコードを日付プログラムに置き換えます。線に注意してください―。。。その時点でコードが置き換えられているため、「動作しましたか?」は表示されません。代わりに、「date -u」の実行結果が表示されます。


1

ここに画像の説明を入力してくださいfork()

実行中のプロセスのコピーを作成します。実行中のプロセスはプロセスと呼ばれ、新しく作成されたプロセスは子プロセスと呼ばれます。2つを区別する方法は、戻り値を調べることです。

  1. fork() 親の子プロセスのプロセス識別子(pid)を返します

  2. fork() 子では0を返します。

exec()

プロセス内で新しいプロセスを開始します。現在のプロセスに新しいプログラムをロードし、既存のプログラムを置き換えます。

fork()+ exec()

新しいプログラムを起動するときは、まずfork()、新しいプロセスを作成し、次にexec()実行するはずのプログラムバイナリをメモリにロードして実行します。

int main( void ) 
{
    int pid = fork();
    if ( pid == 0 ) 
    {
        execvp( "find", argv );
    }

    //Put the parent to sleep for 2 sec,let the child finished executing 
    wait( 2 );

    return 0;
}

0

典型的な例は、理解するfork()exec()概念があるシェル、ユーザーは通常、system.Theのシェルにログインした後に実行するコマンドインタプリタプログラムの最初の単語解釈し、コマンドラインを通り、コマンド

多くのコマンドについては、シェル フォークと子プロセスの幹部名は、コマンドのパラメータとしてコマンドラインで残りの単語を処理することに関連付けられたコマンド。

シェルはコマンドの3種類が可能になります。まず、コマンドは、ソースコード(Cプログラムなど)のコンパイルによって生成されたオブジェクトコードを含む実行可能ファイルにすることができます 。第2に、コマンドは、一連のシェルコマンドラインを含む実行可能ファイルにすることができます。最後に、コマンドは内部シェルコマンドにすることができます(実行可能ファイルex-> cdlsなどの代わりに)。

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