Linuxでは、ディスクからブロックを読み取る必要がある場合、プロセスの状態はどうなりますか?ブロックされていますか?もしそうなら、実行する別のプロセスはどのように選択されますか?
回答:
ファイル記述子が返されるのを待っている間、read()
またはwrite()
そこから返される間、プロセスは「D」または「ディスクスリープ」と呼ばれる特別な種類のスリープ状態になります。このような状態にある間はプロセスを強制終了または中断できないため、これは特別です。ioctl()からの戻りを待機しているプロセスも、この方法でスリープ状態になります。
これの例外は、ファイル(端末やその他のキャラクターデバイスなど)がO_NONBLOCK
モードで開かれるときであり、デバイス(モデムなど)が初期化するのに時間が必要であると想定されたときに渡されます。ただし、質問でブロックデバイスを指定しました。また、ioctl()
非ブロックモードで開かれたfdでブロックされる可能性のあるものを試したことはありません(少なくとも故意ではありません)。
別のプロセスがどのように選択されるかは、使用しているスケジューラー、およびそのスケジューラー内で重みを変更するために他のプロセスが何を行ったかに完全に依存します。
特定の状況下での一部のユーザー空間プログラムは、再起動されるまで、この状態が永遠に続くことが知られています。これらは通常、他の「ゾンビ」と一緒にグループ化されますが、技術的に消滅していないため、この用語は正しくありません。
プロセスがディスクからデータをフェッチする必要がある場合、操作の完了には長い時間がかかる可能性があるため、CPUでの実行を効果的に停止して他のプロセスを実行できます。ディスクのシーク時間は少なくとも5ミリ秒が一般的で、5ミリ秒は1000万ですCPUサイクル、プログラムの観点からの永遠性!
プログラマーの観点から(「ユーザー空間内」とも呼ばれます)、これはブロッキングシステムコールと呼ばれます。write(2)
(同じ名前のシステムコールの薄いlibcラッパーである)を呼び出した場合、プロセスはその境界で正確に停止しません。カーネルでは、システムコールコードを実行し続けます。ほとんどの場合、特定のディスクコントローラードライバー(ファイル名→ファイルシステム/ VFS→ブロックデバイス→デバイスドライバー)に至るまで、ディスク上のブロックをフェッチするコマンドは適切なハードウェアに送信されます。ほとんどの場合、高速操作。
次に、プロセスはスリープ状態になります(カーネル空間では、ブロッキングはスリープと呼ばれます-カーネルの観点からは「ブロック」されることはありません)。ハードウェアが最終的に適切なデータをフェッチすると、プロセスは実行可能としてマークされ、スケジュールされます。最終的に、スケジューラはプロセスを実行します。
最後に、ユーザー空間では、ブロッキングシステムコールが適切なステータスとデータを返し、プログラムフローが続行されます。
最もI / Oシステムコールを呼び出すことが可能である非ブロックモード(参照O_NONBLOCK
にopen(2)
してfcntl(2)
)。この場合、システムコールはすぐに戻り、ディスク操作の送信のみを報告します。プログラマは、操作が正常に完了したかどうかを後で明示的にチェックし、その結果を(たとえばでselect(2)
)フェッチする必要があります。これは、非同期またはイベントベースのプログラミングと呼ばれます。
D状態(TASK_UNINTERRUPTIBLE
Linux状態名で呼ばれる)に関するここでのほとんどの回答は正しくありません。Dの状態は、そのコードパスが場合のみ、カーネル空間コードパスにトリガされる特別なスリープモードで中断することができない(それはプログラムにあまりにも複雑になるので)、それは非常にするためにブロックすることを期待して、短時間。ほとんどの "D状態"は実際には見えないと思います。それらは非常に短命であり、「トップ」などのサンプリングツールでは観察できません。
いくつかの状況では、D状態で強制終了できないプロセスに遭遇する可能性があります。NFSはそのことで有名であり、何度も遭遇しました。常にローカルディスクに到達して高速エラー検出(SATAではエラータイムアウトは約100ミリ秒になる)を想定している一部のVFSコードパスと、実際にネットワークからデータをフェッチするNFSの間には、セマンティッククラッシュがあると思いますより回復力があり、回復に時間がかかります(300秒のTCPタイムアウトが一般的です)。Linux 2.6.25で導入された状態のクールなソリューションについては、この記事をお読みくださいTASK_KILLABLE
。この時代の前に、カーネルスレッドにSIGKILLを送信することにより、NFSプロセスクライアントに実際に信号を送信できるハックがありましたが、rpciod
その醜いトリックを忘れていました。…
/proc/stat
かどうかに関係なく)はすべてD状態として報告されると想定しても安全でしょうか?
I / Oを実行するプロセスはD状態(割り込み不可能なスリープ)に置かれ、CPUにプログラムの実行に戻るように指示するハードウェア割り込みがあるまで、CPUを解放します。man ps
その他のプロセス状態については、を参照してください。
カーネルによっては、実行可能なプロセスの実行キューを追跡するプロセススケジューラがあります。これは、スケジューリングアルゴリズムとともに、どのCPUにどのプロセスを割り当てるかをカーネルに伝えます。考慮すべきカーネルプロセスとユーザープロセスがあります。各プロセスにはタイムスライスが割り当てられます。タイムスライスは、使用が許可されているCPU時間のチャンクです。プロセスがすべてのタイムスライスを使用すると、スケジューリングアルゴリズムで期限切れとしてマークされ、優先順位が低くなります。
では2.6カーネル、そこにあるO(1)時間複雑スケジューラは、それほど関係なく、あなたが実行してアップ持っているか多くのプロセス、それは一定の時間内にCPUを割り当てません。ただし、2.6はプリエンプションを導入し、CPUロードバランシングは簡単なアルゴリズムではないため、さらに複雑です。いずれにせよ、それは効率的であり、I / Oを待機している間、CPUはアイドル状態のままになりません。
他の人がすでに説明したように、「D」状態(無停電スリープ)のプロセスは、psプロセスのハングの原因です。私には、RedHat 6.xと自動マウントされたNFSホームディレクトリで何度も発生しました。
D状態のプロセスをリストするには、次のコマンドを使用できます。
cd /proc
for i in [0-9]*;do echo -n "$i :";cat $i/status |grep ^State;done|grep D
プロセスの現在のディレクトリ、および問題のあるマウントされたNFSディスクを知るには、次の例のようなコマンドを使用します(31134をスリーププロセス番号に置き換えます)。
# ls -l /proc/31134/cwd
lrwxrwxrwx 1 pippo users 0 Aug 2 16:25 /proc/31134/cwd -> /auto/pippo
関連するマウントされたnfsファイルシステムに-f(強制)スイッチを指定してumountコマンドを実行すると、スリーププロセスをウェイクアップできることがわかりました。
umount -f /auto/pippo
ファイルシステムはビジーのためアンマウントされませんでしたが、関連するプロセスがウェイクアップし、再起動せずに問題を解決することができました。
プロセスがシングルスレッドであり、ブロックI / Oを使用しているとすると、プロセスはI / Oが完了するのを待ってブロックします。カーネルは、ナイス、優先度、前回の実行時間などに基づいて、その間に実行する別のプロセスを選択します。他に実行可能なプロセスがない場合、カーネルは何も実行しません。代わりに、マシンがアイドル状態であることをハードウェアに通知します(これにより、消費電力が低下します)。
I / Oの完了を待機しているプロセスは、通常、ps
やなどの状態Dで表示されtop
ます。
はい、IOを待機しているタスクはブロックされ、他のタスクが実行されます。次のタスクの選択は、Linuxスケジューラによって行われます。