APUE 5.4章のラインバッファについて:
- ラインバッファリング。この場合、標準I / Oライブラリは、入力または出力で改行文字が見つかったときにI / Oを実行します。これにより、(標準I / O fputc関数を使用して)一度に1文字を出力でき、実際のI / Oは各行の書き込みが完了したときにのみ発生することがわかります。ラインバッファリングは通常、ストリームが標準入力や標準出力などの端末を参照するときに使用されます。行バッファリングには2つの注意事項があります。まず、各行を収集するために標準I / Oライブラリによって使用されるバッファサイズが固定されているため、改行文字を書き込む前にそのバッファを埋めるとI / Oが発生する可能性があります。次に、(a)バッファリングされていないストリームまたは(b)ラインバッファリングストリーム(カーネルからデータを要求する必要がある)から標準I / Oライブラリを介して入力が要求されるたびに、すべてのラインバッファリング出力ストリームがフラッシュされます。 (b)上位修飾子を使用する理由は、要求されたデータがすでにバッファにある可能性があるため、カーネルからデータを読み取る必要がないためです。明らかにバッファリングされていないストリーム(項目(a))のすべての入力は、カーネルからデータを取得する必要があります。
私はこれら2つの警告をよく理解していません。誰でも例をあげることができますか?
答え1
- デフォルトでは、たとえば、プログラムが端末にテキストを一度に1文字ずつ非常に遅く書き込んでいて、行の長さが520文字の場合、ライブラリはプログラムの端末に最初の512文字を書き込むことができます。行の書き込み(または生成)を終了する前に。
- これは、プログラムが一度に1文字(または他の小さな部分)で端末にテキストを書き込み、次に端末(キーボードなど)から読み取ると、ライブラリが端末に次の部分を書き込むことを意味します。プログラムがこれまでに行った結果、出力ラインが生成されました。端末に書かれた行の中には入力が必要な場合もありますが、時にはそうではない可能性があるため、これは通常必要なものです。
答え2
2つの注意事項を調べる前に留意すべき3つのことがあります。
バッファリングされていないストリームコールシステムコールすべて read
またはwrite
。そして、ラインバッファリングされたストリームはそれぞれにあります。ワイヤー(バッファが改行文字に会うたびに)
また、stdin
とはstdout
両方とも標準I / Oストリームであり、通常はラインバッファリングされています。これらのストリームは、プロセスの開始時に自動的に開きます。
最後に、APUEはUNIX学習のための聖書ですが、一部は時代遅れです。私は私の答えが最新であると主張しません。私はあなたの質問が教科書の文脈内で適切に答えられるように本の例を提示しようとします。
最初の警告
あなたの見積もりに記載されているように制限があります。どのくらい1行だけです。制限を超えると、ラップと同じ効果が発生します。
最初の警告の例を開始する前に、
write
システムコールが実際にキューに入っていることを覚えておく必要があります(APUE第3章、セクション6、p86)。
Jasmine
30秒ごとに文字を書くプログラムがあるとしましょう。stdout
Jasmine
"Hello!\n" (7 バイト) 書き込みを完了するには 210 秒かかります。
バッファに制限があることに注意してください。バッファが10バイトに制限されると、カーネルは210秒待ってからwrite
最後に(改行文字に会った後)単一の呼び出しを発行できます。これは予想される動作です。
ただし、バッファが4バイトに制限されている場合、カーネルは発行されます4 バイトwrite
("Hell") の後に 1 回呼び出し、改行文字 ("\n") の後にもう一度呼び出します。
これが最初の警告です。
ユーザーはwrite
このメッセージが一度だけ表示されることを期待できます(ターミナルに「Hello!\ n」が印刷されます)。例で示したように、これは本当ではありません。システム使用量に応じて、ユーザーは210秒以内に端末に印刷された2つの出力を表示できます。これは、stream()がラインバッファであるにもかかわらず、stdout
そのラインの内容が制限(4バイト制限)を超えるためです。標準 I/O ライブラリは、write
改行文字が発生したかのように 4 バイトごとに呼び出されます。この例では合計 7 バイト ("Hello!\n") があるため、2 回の書き込み呼び出しが発生します。
2番目の警告
2番目の警告の鍵は次のとおりです。相互作用そしてkernel
。
kernel
相互作用に応じて動作が異なり、行バッファに別の「予期しない」書き込みが発生します。
これはあなたが引用した2番目の警告です。
kernel
すべての行バッファストリームは2回フラッシュされます。
- バッファリングされていない標準I / Oを介して入力が要求された場合。
- ラインバッファリングされた標準I / Oを介して入力が要求された場合。
次のように書き換えることができます。
kernel
次の前提条件に従って、すべての行バッファストリームがフラッシュされます。
- 入力を要求します
kernel
。- 要求はバッファリングされていないか、ラインバッファリングされた標準I / Oストリームを介して行われます。
最初の要件は「カーネルからデータを要求する必要があります」です。これにより、ラインバッファ標準I / Oの例外が可能になります。
例外はkernel
〜しないだろう要求にデータが必要ない場合はフラッシュしますkernel
。これは、行バッファにバッファに格納されているすべてのデータがある場合に考えられます。
簡単な例として、ラインバッファストリームのバッファに「World」文字があるとします。ユーザー(呼び出し元)はストリームから1バイトの読み取りを要求します。要求されたシングルバイト(「W」)を返すストリームには助けは必要ありません
kernel
。この場合、kernel
行バッファストリームはフラッシュされません。
この例外を念頭に置いて、最初の警告の例を続行します。
(バッファ制限を10バイトに保つ必要があります)
「Hello!\n」を出力した後、プログラムはJasmine
「Name?」をstdout
。
「名前?」は改行がなく、10バイト制限よりも小さいです。標準I / Oライブラリはまだ呼び出しを発行していませんwrite
。
その後Jasmine
(別のラインバッファストリーム)で入力が要求され、次のようにstdin
なります。
- ストリームの行バッファ
stdin
が空なのでデータを要求していますkernel
。 kernel
すべてのオープンラインバッファストリーム( "Name?"を含むstdout
)をフラッシュします。- その結果、「名前?」が端末に出力される。
kernel
端末(キーボード)でユーザー入力を待ちます。
2番目の警告です。
ユーザーの立場ではwrite
まだ情報が公開されていないため、端末で「名前?」というメッセージを見るのは混乱する可能性があります。残念ながら、kernel
問題は、write
要求されたデータを取得しようとする前に、現在開いているすべての行バッファストリームが呼び出されることです。これは、ラインバッファストリーミングと相互作用のための2つの前提条件がすでに満たされているkernel
ためです。kernel