C の fork()

C の fork()

Fork システム コールは、Linux および Unix システムで新しいプロセスを作成するために使用されます。 子プロセス 、fork() 呼び出しを行うプロセス (親プロセス) と同時に実行されます。新しい子プロセスが作成されると、両方のプロセスが fork() システム コールに続いて次の命令を実行します。

子プロセスは、親プロセスで使用するものと同じ pc (プログラム カウンタ)、同じ CPU レジスタ、および同じオープン ファイルを使用します。パラメーターは取らず、整数値を返します。

以下は、fork() によって返されるさまざまな値です。

  • 負の値 : 子プロセスの作成に失敗しました。
  • ゼロ : 新しく作成した子プロセスに戻ります。
  • 正の値 : 親または呼び出し元に返されます。値には、新しく作成された子プロセスのプロセス ID が含まれます。

フォークプロセスの作成

注記: fork() はスレッドベースの関数であり、正しい出力を取得するには、ローカル システムでプログラムを実行します。

上記のプログラムは Windows 環境ではコンパイルできないことに注意してください。

C の fork() の例

C




#include> #include> #include> int> main()> {> > > // make two process which run same> > // program after this instruction> > pid_t p = fork();> > if> (p <0){> > perror> (> 'fork fail'> );> > exit> (1);> > }> > printf> (> 'Hello world!, process_id(pid) = %d '> ,getpid());> > return> 0;> }>

出力

Hello world!, process_id(pid) = 31 Hello world!, process_id(pid) = 32 

例 2: hello が出力される回数を計算します。

C




#include> #include> #include> int> main()> {> > fork();> > fork();> > fork();> > printf> (> 'hello '> );> > return> 0;> }>

出力

hello hello hello hello hello hello hello hello 

説明

「hello」が出力される回数は、作成されたプロセスの数と同じです。プロセスの合計数 = 2 n ここで、n は fork システム コールの数です。したがって、ここでは n = 3, 2 3 = 8 3 つの行にいくつかのラベル名を付けてみましょう。

fork (); // Line 1 fork (); // Line 2 fork (); // Line 3 L1 // There will be 1 child process /  // created by line 1. L2 L2 // There will be 2 child processes /  /  // created by line 2 L3 L3 L3 L3 // There will be 4 child processes // created by line 3 

したがって、合計 8 つのプロセス (新しい子プロセスと 1 つの元のプロセス) があります。プロセス間の関係をツリー階層として表現したい場合は、次のようになります。 メインプロセス: P0 1 番目のフォークによって作成されたプロセス: P1 2 番目のフォークによって作成されたプロセス: P2、P3 3 番目のフォークによって作成されたプロセス: P4、P5、P6、P7

 P0 / |  P1 P4 P2 /   P3 P6 P5 / P7 

例 3: 次のプログラムの出力を予測します。

C




#include> #include> #include> #include> void> forkexample()> {> > pid_t p;> > p = fork();> > if> (p <0)> > {> > perror> (> 'fork fail'> );> > exit> (1);> > }> > // child process because return value zero> > else> if> ( p == 0)> > printf> (> 'Hello from Child! '> );> > > // parent process because return value non-zero.> > else> > printf> (> 'Hello from Parent! '> );> }> int> main()> {> > forkexample();> > return> 0;> }>

出力

Hello from Parent! Hello from Child! 

注記: 上記のコードでは、子プロセスが作成されます。 fork() は、子プロセスでは 0 を返し、親プロセスでは正の整数を返します。ここでは、親プロセスと子プロセスが同時に実行されているため、2 つの出力が可能です。したがって、OS が最初に親プロセスに制御を与えるのか、それとも子プロセスに制御を与えるのかはわかりません。

親プロセスと子プロセスは同じプログラムを実行していますが、それはそれらが同一であることを意味するわけではありません。 OS はこれら 2 つのプロセスに異なるデータと状態を割り当て、これらのプロセスの制御フローは異なる場合があります。次の例を参照してください。

例 4: 次のプログラムの出力を予測します。

C




#include> #include> #include> #include> > void> forkexample()> {> > int> x = 1;> > pid_t p = fork();> > if> (p <0){> > perror> (> 'fork fail'> );> > exit> (1);> > }> > else> if> (p == 0)> > printf> (> 'Child has x = %d '> , ++x);> > else> > printf> (> 'Parent has x = %d '> , --x);> }> int> main()> {> > forkexample();> > return> 0;> }>

出力

Parent has x = 0 Child has x = 2 

または

出力

Child has x = 2 Parent has x = 0 

ここで、2 つのプロセスのデータ/状態は異なるため、1 つのプロセスでのグローバル変数の変更は他の 2 つのプロセスには影響しません。また、親と子が同時に実行されるため、2 つの出力が可能です。

fork() と exec()

fork システムコールは新しいプロセスを作成します。 fork() によって作成される新しいプロセスは、戻り値を除いて現在のプロセスのコピーです。一方、exec() システムコールは、現在のプロセスを新しいプログラムに置き換えます。

C fork() に基づく問題

1. プロセスは次のコードを実行します。

C




for> (i = 0; i fork();>

作成される子プロセスの総数は次のとおりです。 (ゲート-CS-2008)

(A)n
(B) 2^n – 1
(C) 2^n
(D) 2^(n+1) – 1

解決策については、これを参照してください。

2. 次のコード部分を考えてみましょう。

C




if> (fork() == 0) {> > a = a + 5;> > printf> (> '%d, %d '> , a, &a);> }> else> {> > a = a –5;> > printf> (> '%d, %d '> , a, &a);> }>

u、v を親プロセスによって出力される値、x、y を子プロセスによって出力される値とする。次のうち正しいのはどれですか? (ゲート-CS-2005)

(A) u = x + 10 および v = y
(B) u = x + 10 および v != y
(C) u + 10 = x および v = y
(D) u + 10 = x および v != y

解決策については、これを参照してください。

3. 以下のプログラムの出力を予測します。

C




#include> #include> int> main()> > > fork();> > fork() && fork()>

解決策についてはこれを参照してください

関連記事 :

  • fork() と Pipe() をデモする C プログラム
  • C のゾンビおよび孤立プロセス
  • fork() とそれを使用して作成されたメモリ共有白黒プロセス