C標準I/Oバッファ:フルバッファとラインバッファ
3389 ワード
ISO C標準I/Oはフルバッファとラインバッファを提供する
フルバッファ:I/O操作を行う場合、I/Oバッファが満たされている場合にのみ、本格的なI/O操作が行われます.したがって、フルバッファのバッファは、標準I/Oルーチンによって自動的にリフレッシュされ得る.すなわち、バッファが満たされると、関数fflushを呼び出してリフレッシュする方法もある.
行バッファ:I/O操作時、入出力に改行があった場合に行い、本格的なI/O操作を行います.ラインバッファの場合、標準I/Oは1ラインあたりのバッファ長が固定されているため、バッファが満たされていれば改行が発生しなくてもリフレッシュバッファと交換されます.
もちろん標準I/Oにはバッファなしタイプも用意されていますが、文字をバッファリングしないタイプです.
では、フルバッファとローバッファは、I/O操作のどこに使われているのでしょうか.
ISO C要求:標準入力および出力がインタラクティブデバイス(端末デバイス)に関係しない場合にのみ、それらはフルバッファである. 標準エラーはフルバッファではありません.
しかし、これは、インタラクティブデバイスに関連する場合、標準入出力が行バッファであるか、バッファを持たないか、標準エラーの場合、行バッファであるか、バッファを持たないかを示していません.多くのシステム(FreeBSD、Linux、Mac OS、Solaris)では、デフォルトで次のタイプのバッファが使用されます.標準入出力が端末装置に関連する場合、それらは行バッファであり、そうでなければ全バッファである. 標準エラーバッファなし.
shellはプロセスごとに3つのファイル記述子を定義していることを知っています:0,1,2.この3つのファイル記述子は、プロセスの標準入力、標準出力、標準エラー出力にそれぞれ関連しています.unistd.hヘッダファイルの3つの定数をそれぞれstdIN_に置き換えるFILENO,stdOUT_FILENO,stdERR_FILENO記号.ISO Cではそれぞれstdin,stdout,stderrに対応する.
apue chapter 8の一例から、上述した全バッファと行バッファの違いを深く体得することができる.
次のように入力すると、./unix8_1の場合、出力結果は次のとおりです.
anonymalias
before fork()...
parent process id:7222 process id:7223, glob:7, var:9
parent process id:5200 process id:7222, glob:6, var:8
次のように入力すると、./unix8_1>tempの場合、tempファイルを表示し、次のように出力します.
anonymalias before fork()... parent process id:7237 process id:7238, glob:7, var:9 before fork()... parent process id:5200 process id:7237, glob:6, var:8
なぜなら、unix 8を実行しているからです.1の場合、デフォルトの標準出力は端末装置であるディスプレイである.このとき、標準出力バッファは行バッファであり、22行目の出力が実行されるとバッファがリフレッシュされる.
で、./unix8_1>temp時に標準出力がファイルにリダイレクトされ、インタラクティブデバイスではありません.このとき、標準出力バッファはフルバッファであり、22行目まで実行した場合、出力は行われず、バッファはリフレッシュされない.出力は、バッファが満たされるかfflushが行われるまで行われません.
一方、forkがサブプロセスを生成すると、サブプロセスは親プロセスのデータ空間をコピーします.もちろん、親プロセスが開いているファイル記述子に対応するバッファも含まれます../unix8_1時の22行目の出力後、バッファはリフレッシュされてクリアされるので、サブプロセスはこのバッファをコピーしません.実行中./unix8_1>tempの場合、22行目の標準出力のバッファはフルバッファであり、リフレッシュされないため、サブプロセスはこのバッファをコピーし、プログラム終了時に出力バッファをリフレッシュします.最後に「before fork()...」を2回出力し、親プロセスと子プロセスには独自のバッファがあるからです.
実行するには./unix8_1および./unix8_1>tempの出力結果と同じように、22行目の後ろにfflushを付けることができます.
anonymalias before fork()... parent process id:7222 process id:7223, glob:7, var:9
parent process id:5200 process id:7222, glob:6, var:8
皆さんのご叱正を歓迎します.
11:05 24/09/2012 anonymalias @lab
フルバッファ:I/O操作を行う場合、I/Oバッファが満たされている場合にのみ、本格的なI/O操作が行われます.したがって、フルバッファのバッファは、標準I/Oルーチンによって自動的にリフレッシュされ得る.すなわち、バッファが満たされると、関数fflushを呼び出してリフレッシュする方法もある.
行バッファ:I/O操作時、入出力に改行があった場合に行い、本格的なI/O操作を行います.ラインバッファの場合、標準I/Oは1ラインあたりのバッファ長が固定されているため、バッファが満たされていれば改行が発生しなくてもリフレッシュバッファと交換されます.
もちろん標準I/Oにはバッファなしタイプも用意されていますが、文字をバッファリングしないタイプです.
では、フルバッファとローバッファは、I/O操作のどこに使われているのでしょうか.
ISO C要求:
しかし、これは、インタラクティブデバイスに関連する場合、標準入出力が行バッファであるか、バッファを持たないか、標準エラーの場合、行バッファであるか、バッファを持たないかを示していません.多くのシステム(FreeBSD、Linux、Mac OS、Solaris)では、デフォルトで次のタイプのバッファが使用されます.
shellはプロセスごとに3つのファイル記述子を定義していることを知っています:0,1,2.この3つのファイル記述子は、プロセスの標準入力、標準出力、標準エラー出力にそれぞれ関連しています.unistd.hヘッダファイルの3つの定数をそれぞれstdIN_に置き換えるFILENO,stdOUT_FILENO,stdERR_FILENO記号.ISO Cではそれぞれstdin,stdout,stderrに対応する.
apue chapter 8の一例から、上述した全バッファと行バッファの違いを深く体得することができる.
#include
#include
#include
int glob = 6;
char buf[] = "anonymalias
";
int main()
{
int var;
pid_t pid;
var = 8;
if(write(STDOUT_FILENO, buf, strlen(buf)) != strlen(buf))
{
fprintf(stderr, "write error");
return 0;
}
printf("before fork()...
");
if((pid = fork()) == -1)
{
fprintf(stderr, "fork error");
return 0;
}
if(pid == 0)
{
glob++;
var++;
}
else
{
sleep(2);
}
printf("parent process id:%d ", getppid());
printf("process id:%d, glob:%d, var:%d
", getpid(), glob, var);
return 0;
}
次のように入力すると、./unix8_1の場合、出力結果は次のとおりです.
anonymalias
before fork()...
parent process id:7222 process id:7223, glob:7, var:9
parent process id:5200 process id:7222, glob:6, var:8
次のように入力すると、./unix8_1>tempの場合、tempファイルを表示し、次のように出力します.
anonymalias before fork()... parent process id:7237 process id:7238, glob:7, var:9 before fork()... parent process id:5200 process id:7237, glob:6, var:8
なぜなら、unix 8を実行しているからです.1の場合、デフォルトの標準出力は端末装置であるディスプレイである.このとき、標準出力バッファは行バッファであり、22行目の出力が実行されるとバッファがリフレッシュされる.
で、./unix8_1>temp時に標準出力がファイルにリダイレクトされ、インタラクティブデバイスではありません.このとき、標準出力バッファはフルバッファであり、22行目まで実行した場合、出力は行われず、バッファはリフレッシュされない.出力は、バッファが満たされるかfflushが行われるまで行われません.
一方、forkがサブプロセスを生成すると、サブプロセスは親プロセスのデータ空間をコピーします.もちろん、親プロセスが開いているファイル記述子に対応するバッファも含まれます../unix8_1時の22行目の出力後、バッファはリフレッシュされてクリアされるので、サブプロセスはこのバッファをコピーしません.実行中./unix8_1>tempの場合、22行目の標準出力のバッファはフルバッファであり、リフレッシュされないため、サブプロセスはこのバッファをコピーし、プログラム終了時に出力バッファをリフレッシュします.最後に「before fork()...」を2回出力し、親プロセスと子プロセスには独自のバッファがあるからです.
実行するには./unix8_1および./unix8_1>tempの出力結果と同じように、22行目の後ろにfflushを付けることができます.
22 printf("before fork()...
");
23 fflush(stdout);
このように出力された結果はすべてanonymalias before fork()... parent process id:7222 process id:7223, glob:7, var:9
parent process id:5200 process id:7222, glob:6, var:8
皆さんのご叱正を歓迎します.
11:05 24/09/2012 anonymalias @lab