1

stdin と言うときは、fd=0 で参照されるストリームを指しています。

ブロックデバイスとキャラクターデバイスをカバーするOSコースを受講しています。具体的には、キーボードはキャラクターデバイスであると述べました。しかし、readsyscall を見せられたとき、それがブロック デバイスまたはブロック デバイス上のファイルである限り、カーネルは何から読み取っていてもかまわないと言われました。

与えられたコードは次のとおりです。

#include <stdlib.h>
#include <unistd.h>

const int BUFFSIZE = 5;

int main () {
  int fd, n;
  char buffer[BUFFSIZE];

  int stdin = 0;
  int stdout = 1;
  int stderr = 2;

  do {
    n = read (0, buffer, BUFFSIZE);
    if (n < 0) {
      write (stderr, "Error occurred\n", 10);
    } else {
      write (stdout, "Entered if\n", 20);
      write (stdout, buffer, n);
    }
  } while (n > 0);
  return 0;
}

私の質問は、Linux は標準入力 (fd = 0) をどのように扱うのですか? キャラクターデバイスとして扱われますか、それともカーネルが何らかのバッファリングを行いますか (これは、コードを実行したときに得られた結果から判断することで可能性が高いと思われます)。

さらに、一般的なキャラクター デバイスからの読み取りに read syscall を使用できるかどうかを知っておくと便利です。その場合、入力はバッファリングされていますか?

4

2 に答える 2

6

カーネルは通常、キャラクターデバイス上でバッファリングをほとんどまたはまったく行いません。

カーネルは、ファイルシステム内のファイルから読み取るときに、一定量のバッファリングを行います。

プロセスごとに異なるため、デバイスの標準入力がどのようなものかは言えません。デフォルトでは、通常、fd 0 はユーザーのキーボードであり、キャラクター デバイスです。しかし、私が言うなら

program < file

fd 0 は通常のファイルです。私が言うなら

program < /dev/hda0

fd 0 はブロックデバイスです。そして、私がそれに取り組んでいれば、おそらく fd 0 をネットワークソケットに接続することもできたでしょう。

Linux にも がありますが、これもデバイスではありません。それが何であれ、実際のデバイスへのシンボリックリンクのように見えます。/proc/pid/fd/0/dev


補遺: 特定のデバイスがバッファリングされているかどうかは、そのデバイスのドライバがどのように記述されているかによって異なります。特定のドライバーは、何らかの形式のバッファリングを実装する場合と実装しない場合があります。さらに、バッファリングが実際に使用されるかどうかは、他の要因によって終了する可能性があります。(たとえば、Unix ターミナル ドライバはデフォルトですべてライン バッファリングされていますが、ドライバを「cbreak」または「raw」モードにすると、そのバッファリングはオフになります)。キャラクターデバイスまたはブロックデバイスがバッファリングされている、またはバッファリングされていないという一般的な声明を出すことはできないと思います。


補遺 2: レイヤーを剥がし始めると、かなり複雑になる可能性があります。Unix は、私が意味することを行うことと、シンプルに保つこととの間の適切なバランスを保つために、非常に努力しています (そして、一般的には非常に良い仕事をしています)。たとえば、ライン バッファリングされていないread()端末を使用していて、10 文字を要求した場合、利用できるのは 3 文字だけで、3が返されます。これは正しいことですが、どこかにまだバッファがあることを示唆しています。これらの 3 文字は、入力してから読むまでの間に蓄積された場所です。さらに、3 つだけを要求したのに 10 個しか利用できなかった場合、状況によっては残りの 7 個が保存されると思います。これもまた、かなりの量のカーネル レベルのバッファリングを示唆しています。

しかし、生モードでは、文字を十分に速く読まないと、文字を失う可能性があると確信しています. ターミナル ドライバーからネットワーク ソケットに注意を移すと、特定の状況下でread()UDP モード ソケットで実行し、実際の UDP パケットが読み取り要求よりも大きい場合、そこで残りのパケットが失われる可能性があると考えていました。 、 それも。[コメンターは私が間違っているかもしれないと示唆していますが] (一方、TCP モードのソケットは明らかに大量にバッファリングされています!)

つまり、ルールは複雑になる可能性があり、正確な詳細は、使用中の特定のデバイス ドライバーだけでなく、潜在的に無数の他の詳細にも依存します。

于 2016-04-11T22:03:20.350 に答える
1

Unix には真の stdin はありません。C ランタイム ライブラリは、プロセスの最初 (0 番目) のファイル記述子に関連付けられているシンボル stdin を定義します。

慣例により、Unix シェルはプロセスを作成するときに 3 つのファイルをセットアップします。また、慣例により、これらは stdin、stdout、および stderr と呼ばれます。

UNIX プロセスがこれら 3 つのファイルを持っている必要はありません。ファイル 0、1、または 2 を開かずにプロセスを作成する独自のシェルを作成することは完全に可能です。

stdin の動作は、関連付けられている「ファイル」(データ ストリーム) のタイプによって異なります。Stdin は、キーボードにマップすることも、ファイルにマップすることもできます。どちらの場合でも、データを読み取ることができます。後者でのみ fseek を実行できます。

于 2016-04-11T22:01:04.377 に答える