2011-02-22 3 views
1

私はプロセスのバイナリツリーを作成するためにfork()を使って簡単なCプログラムを書いています。私は必要なすべての出力を得ることができます(プロセスの親、親、およびその2人の子供)。残念なことに、各フォークされたプロセスは、列見出しを印刷する必要があります。ヘッダーのprintfが1回だけ実行されることを確認するにはどうすればよいですか?fork()は、各プロセスのカラムヘッダーを出力します。

# include <stdio.h> 
# include <stdlib.h> 
# include <sys/types.h> 
# include <unistd.h> 
# include <sys/wait.h> 

int main(int argc, char *argv[]){ 

//Declarations 
int i; 
int child_1_pid, child_2_pid; 
int num_levels = atoi(argv[1]); 

//Output banners 
//execlp("/bin/echo", "echo", "Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID", (char *) NULL); 
//if(getpid() > 0) 
printf("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID"); 

//Creates binary tree of processes 
for(i = 0; i < num_levels; i++){ 
    if((child_1_pid = fork()) && (child_2_pid = fork())){ 
     printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid); 
     sleep(2); //prevents parent from terminating before child can get ppid (parent's pid) 
     break; //why?  
    } 
}//end for 

printf("\n"); //EXPLAIN ME!! 
exit(0); 
}//end main 

あり、いくつかのより多くのコードが(エラーが実際にチェック)のですが、私の本当の問題は、出力バナーセクションの下のprintfは、このような出力を与え、複数回実行していることである(ただし、正しく整列):

Level Procs Parent Child1 Child2 
No. ID ID ID ID 
No. ID ID ID ID 
No. ID ID ID ID 
No. ID ID ID ID 
No. ID ID ID ID 
No. ID ID ID ID 
No. ID ID ID ID 
0 30796 24743 30797 30798 
1 30797 30796 30799 30800 
1 30798 30796 30801 30802 

私はいくつかのアイデア(バナーセクションの下にコメントアウトされているものを含む)を試しましたが、何も動作していないようで、ほとんどの "修正"が問題をさらに悪化させます。

+0

あなたが見ている奇妙な印刷を説明できると思います。 'sleep(2)'と 'printf(" \ n ")'は 'fflush(0)'になります。 – nmichaels

+3

'printf'の修正後に' fflush(stdout); 'を追加しますか? stdioバッファが子プロセスにコピーされ、そこにのみ印刷されることがあります。 –

+0

はい! fflushを追加すると、複数の印刷問題を解決できます。余分な空白行を避けるため、\ nプリントを一番下に削除しました。また、以下に述べるように、プロセス印刷行の後にfflushを置く必要がありました(forループ内)。 –

答えて

3

まず、forループ内ifは動作しません。フォークの後では、親プロセスの子PIDと子プロセスの0を返します。ループの内側では、最初のフォークは親のchild_1_pidに値を割り当て、2番目の節に進みます。子はifに入っていませんが、次のfor-loopの繰り返しに進みます。 2番目の節でも同じことが起こります。したがって、メインプロセスだけがifの本文に入ることができるはずですが、子プロセスはありません。私はなぜその出力が他のことを示唆しているのだろうか。

は、だからあなたの「バイナリツリー」を得るために、あなたが実際にこれを持っている必要があります。バナーの

// COMPLETELY UNTESTED 
for(i = 0; i < num_levels; i++){ 
    if (!(child_1_pid = fork()) || !(child_2_pid = fork())) { 
     printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid); 
     // A child process, go on to next iteration. 
     continue; 
    } 

    // A parent process. Wait for children, then stop. 
    if (child_1_pid) wait(); 
    if (child_2_pid) wait(); 
    break; 
} 

奇妙な出力がストリームのフラッシュに関係しています。通常、fprintfは改行(\n)、IIRCでのみフラッシュされます。したがって、まだフラッシュされていないフォークの後ろにはまだバッファ内のものがあり、各子はprintf("\n");を実行し、バッファの内容をフラッシュします。

解決策は、最初のprintfの最後に "\ n"を追加するか、を呼び出すか、forループの前にfflush(stdout);を呼び出します。

+0

forループの前にfflushの必要性について完全に正しいです。また、バナープリントステートメントの後に1つ追加する必要がありました。改行のprintfとフラッシュについてのヒントをありがとうございました。 –

+0

これは、最初の 'fork()'呼び出しからの親プロセスだけが短絡のために 'fork()'を2回実行するので、アンバランスなバイナリツリーを作成します。これはあなたの意図かもしれません。 – SiegeX

+0

@SiegeX:そうです。 '||'の代わりに '|'を使うとこれを修正するはずです。 – DarkDust

2

私はこのようなもので少し錆びていますが、ここで試してみてください。あなたのバナーを印刷ラインで:

のprintf( "レベル\ tProcs \ tParent \ tChild1 \ tChild2 \ nこの\にtID \にtID \にtID \にtID");

\nの後のすべてが出力バッファに残っている可能性があります。そのため、各子がフォークされてもまだそのままです。そのprintfの最後に別の\nを追加し、ループ内のprintfの先頭から\nを削除してみてください。

+0

これは正しいアイデアだと思います。上記の答えは、printfが\ nでフラッシュされることを示しているので、正しいと思われます。 –

+0

@ジョンスミス。 @ダークダストは間違いなく私よりも徹底的な答えを持っていた。 – Will

1

置き換えます

printf("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID"); 

で:

puts("Level\tProcs\tParent\tChild1\tChild2\nNo.\tID\tID\tID\tID"); 

は交換してください:

printf("\n%d\t%d\t%d\t%d\t%d", i, getpid(), getppid(), child_1_pid, child_2_pid); 

で:

printf("%d\t%d\t%d\t%d\t%d\n", i, getpid(), getppid(), child_1_pid, child_2_pid); 

削除:あなたはそれがしたいよう

printf("\n"); 
0

読む2.5.1ここに:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html

ノートフォーク後の()1つ前に存在していたところ、二つのハンドルが存在します。アプリケーションは、両方のハンドルにアクセスすることができれば、両方がアクティブなハンドルに最初になることができる状態にあることを保証しなければならない。アプリケーションは、まるでそれがアクティブなハンドルの変更であるかのように、fork()の準備をしなければならない。 (いずれかのプロセスによって実行される唯一のアクションがexec関数または_exit()のいずれかである場合(exit()ではなく)、ハンドルはそのプロセスでは決してアクセスされません)。

これは、 forkに電話する前に、forkの後に両方のプロセスで使用する予定のすべてのストリームでfflushを呼び出す必要があります。

関連する問題