違いは何ですかfork
とはexec
?
fork
基本的にクローニングされた:O
違いは何ですかfork
とはexec
?
fork
基本的にクローニングされた:O
回答:
新しいプロセスを開始する非常にシンプルな方法を提供するという点で、UNIXの精神を使用しfork
、exec
例示しています。
fork
コールは、基本的に同じで、現在のプロセスの複製になり、ほぼすべての方法。すべてがコピーされるわけではありません(たとえば、一部の実装ではリソースの制限)が、できるだけ近いコピーを作成するという考えです。
新しいプロセス(子)は異なるプロセスID(PID)を取得し、古いプロセス(親)のPIDをその親PID(PPID)として持ちます。2つのプロセスはまったく同じコードを実行しているので、戻りコードによってどちらがどちらであるかがわかります。fork
子は0を取得し、親は子のPIDを取得します。もちろん、これはすべて、fork
呼び出しが機能することを前提としています。機能しない場合、子は作成されず、親はエラーコードを受け取ります。
exec
コールは、基本的には新しいプログラムで全体の現在のプロセスを交換する方法です。プログラムを現在のプロセス空間にロードし、エントリポイントから実行します。
だから、fork
そしてexec
多くの場合、現在のプロセスの子として実行する新しいプログラムを取得するために順番に使用されています。シェルは通常find
、次のようなプログラムを実行しようとするたびにこれを行います-シェルがフォークし、子がfind
プログラムをメモリにロードして、すべてのコマンドライン引数、標準I / Oなどを設定します。
ただし、これらを一緒に使用する必要はありません。たとえば、プログラムに親コードと子コードの両方が含まれている場合は、プログラムがing fork
なしでそれ自体に完全に受け入れられexec
ます(実装には注意が必要です。実装ごとに制限がある場合があります)。これはfork
、親がリッスンに戻っている間に特定の要求を処理するためにTCPポートと自分のコピーを単にリッスンするデーモンにかなり多く使用されています(まだ使用されています)。
同様に、彼らは完成している知っているとプログラムがちょうどする必要はありません別のプログラムを実行したいfork
、exec
その後、wait
子供のために。子をプロセススペースに直接ロードできます。
一部のUNIX実装には、fork
コピーオンライトと呼ばれるものを使用する最適化があります。これはfork
、プログラムがその空間の何かを変更しようとするまで、プロセス空間のコピーを遅らせるトリックです。これは、使用してそれらのプログラムのために有用でfork
はないexec
、彼らは全体のプロセス空間をコピーする必要がないという点で。
exec
が次のように呼び出された場合fork
(これがほとんどの場合に発生します)、プロセススペースへの書き込みが発生し、子プロセスにコピーされます。
全体の家族があることに注意してくださいexec
呼び出しは(execl
、execle
、execve
など)が、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
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です。
exec
exec
ターゲットの実行可能ファイルを使用してプロセスを実行するように指示するだけで、2つのプロセスが同じコードを実行したり、同じ状態を継承したりする必要はありません。@Steve Hawkinsが言うように、現在のプロセスでターゲット実行可能ファイルを実行したexec
後に使用できますfork
。
pid < 0
し、fork()
呼び出しが失敗した
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のはるかに詳細な回答の簡略化された「ダミー用」バージョンです)
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のコード{親と同じではない})になります。
これらは一緒に使用され、新しい子プロセスを作成します。最初に、呼び出し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
}
主な違い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」の実行結果が表示されます。
実行中のプロセスのコピーを作成します。実行中のプロセスは親プロセスと呼ばれ、新しく作成されたプロセスは子プロセスと呼ばれます。2つを区別する方法は、戻り値を調べることです。
fork()
親の子プロセスのプロセス識別子(pid)を返します
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;
}
典型的な例は、理解するfork()
とexec()
概念があるシェル、ユーザーは通常、system.Theのシェルにログインした後に実行するコマンドインタプリタプログラムの最初の単語解釈し、コマンドラインを通り、コマンド名
多くのコマンドについては、シェル フォークと子プロセスの幹部名は、コマンドのパラメータとしてコマンドラインで残りの単語を処理することに関連付けられたコマンド。
シェルはコマンドの3種類が可能になります。まず、コマンドは、ソースコード(Cプログラムなど)のコンパイルによって生成されたオブジェクトコードを含む実行可能ファイルにすることができます 。第2に、コマンドは、一連のシェルコマンドラインを含む実行可能ファイルにすることができます。最後に、コマンドは内部シェルコマンドにすることができます(実行可能ファイルex-> cd、lsなどの代わりに)。