web-dev-qa-db-ja.com

Linuxプロセスの状態

Linuxでは、ディスクからブロックを読み取る必要がある場合、プロセスの状態はどうなりますか?ブロックされていますか?もしそうなら、別のプロセスをどのように選択して実行しますか?

83
Blair

read()またはwrite()がファイル記述子の戻りを待っている間、プロセスは "D"または "Disk Sleep"として知られる特別な種類のスリープ状態になります。このような状態にある間、プロセスを強制終了または中断できないため、これは特別です。 ioctl()からの戻りを待機しているプロセスも、この方法でスリープ状態になります。

これの例外は、ファイル(端末や他のキャラクターデバイスなど)が_O_NONBLOCK_モードで開かれ、デバイス(モデムなど)の初期化に時間がかかると想定される場合に渡される場合です。ただし、質問でブロックデバイスを指定しました。また、非ブロックモードで開かれたfdでブロックする可能性が高いioctl()を試したことはありません(少なくとも知らないうちに)。

別のプロセスがどのように選択されるかは、使用しているスケジューラーと、そのスケジューラー内で重みを変更するために他のプロセスが行ったかもしれないものに完全に依存します。

特定の状況下の一部のユーザー空間プログラムは、再起動されるまでこの状態を永久に維持することが知られています。これらは通常、他の「ゾンビ」とグループ化されますが、技術的に無効ではないため、用語は正しくありません。

80
Tim Post

プロセスがディスクからデータを取得する必要がある場合、操作の完了に長い時間がかかる可能性があるため、CPUでの実行が事実上停止し、他のプロセスを実行できます。 CPUサイクル、プログラムの観点からは永遠です!

プログラマーの観点から(「ユーザー空間」とも呼ばれます)、これはブロッキングシステムコールと呼ばれます。 write(2)(同じ名前のシステムコールの薄いlibcラッパー)を呼び出すと、プロセスはその境界で正確に停止しません。カーネル内でシステムコールコードを実行し続けます。ほとんどの場合、特定のディスクコントローラードライバー(ファイル名→ファイルシステム/ VFS→ブロックデバイス→デバイスドライバー)まで進み、ディスク上のブロックを取得するコマンドが適切なハードウェアに送信されます。ほとんどの場合、高速動作。

その後、プロセスはsleep状態になります(カーネル空間では、ブロッキングはスリープと呼ばれ、カーネルの観点からは「ブロック」されません)。ハードウェアが最終的に適切なデータをフェッチすると目覚め、プロセスはrunnableとしてマークされ、スケジュールされます。最終的に、スケジューラーはプロセスを実行します。

最後に、ユーザー空間では、ブロッキングシステムコールが適切なステータスとデータで戻り、プログラムフローが続行します。

ほとんどのI/Oシステムコールをノンブロッキングモードで呼び出すことができますopen(2)O_NONBLOCKおよびfcntl(2))。この場合、システム呼び出しはすぐに戻り、ディスク操作の送信のみを報告します。プログラマは、操作が正常に完了したかどうかを後で明示的に確認し、その結果をフェッチする必要があります(たとえば、select(2)を使用)。これは、非同期またはイベントベースのプログラミングと呼ばれます。

ここでのD状態(Linuxの状態名ではTASK_UNINTERRUPTIBLEと呼ばれる)に言及するほとんどの回答は間違っています。 [〜#〜] d [〜#〜]状態は特別なスリープモードであり、そのコードがカーネルスペースコードパスでのみトリガーされるパスは中断できません(プログラムするには複雑すぎるため)、非常に短い時間だけブロックすることが予想されます。私は、ほとんどの「D状態」は実際には目に見えないと考えています。それらは非常に短命であり、「トップ」などのサンプリングツールでは観察できません。

いくつかの状況では、D状態で殺せないプロセスに遭遇する可能性があります。 NFSはそのことで有名であり、私は何度も遭遇しました。常にローカルディスクに到達し、高速エラー検出(SATAではエラータイムアウトは数百ミリ秒程度)を想定するVFSコードパスと、実際にネットワークからデータを取得するNFSの間にセマンティッククラッシュがあると思います。より回復力があり、回復が遅い(TCP 300秒のタイムアウトが一般的です。)を読む この記事 Linux 2.6.25で導入されたクールなソリューションについてはTASK_KILLABLE状態:この時代以前は、カーネルスレッドrpciodにSIGKILLを送信することで、NFSプロセスクライアントに実際に信号を送信できるハックがありましたが、そのいトリックは忘れてください…

123
zerodeux

I/Oを実行するプロセスはD状態(割り込み不可能なスリープ)になり、プログラムの実行に戻るようにCPUに指示するハードウェア割り込みがあるまでCPUを解放します。見る - man ps 他のプロセス状態の場合。

カーネルに応じて、process schedulerがあり、実行可能なプロセスのrunqueueを追跡します。スケジューリングアルゴリズムと共に、どのプロセスをどのCPUに割り当てるかをカーネルに指示します。考慮すべきカーネルプロセスとユーザープロセスがあります。各プロセスには、使用が許可されているCPU時間のチャンクであるタイムスライスが割り当てられます。プロセスがそのタイムスライスをすべて使用すると、期限切れとしてマークされ、スケジューリングアルゴリズムで優先順位が低くなります。

2.6カーネルには、O(1)時間複雑度スケジューラーがあるため、実行中のプロセスの数に関係なく、一定の時間でCPUを割り当てます。 2.6はプリエンプションを導入し、CPU負荷分散は簡単なアルゴリズムではないため、より複雑です。いずれにせよ、それは効率的であり、I/Oを待つ間、CPUはアイドル状態のままになりません。

7
user224579

他の人がすでに説明したように、「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

ファイルシステムはビジー状態だったためアンマウントされませんでしたが、関連するプロセスが起動し、再起動せずに問題を解決できました。

はい、タスクはread()システムコールでブロックされます。準備ができている別のタスクが実行されるか、または他のタスクが準備されていない場合、アイドルタスク(そのCPU)が実行されます。

通常のブロッキングディスク読み取りでは、タスクが「D」状態になります(他の人が述べているように)。このようなタスクは、CPUを消費していない場合でも、負荷平均に貢献します。

他のタイプのIO、特にttyとネットワークはまったく同じように動作しません-プロセスは最終的に「S」状態になり、中断される可能性があり、負荷平均にカウントされません。

1
MarkR

プロセスがシングルスレッドであり、ブロッキングI/Oを使用していると仮定すると、プロセスはI/Oの完了を待機してブロックします。カーネルは、ナイスネス、優先度、最終実行時間などに基づいて、その間に実行する別のプロセスを選択します。他の実行可能なプロセスがない場合、カーネルは実行しません。代わりに、マシンがアイドル状態であることをハードウェアに通知します(これにより、消費電力が低下します)。

I/Oの完了を待機しているプロセスは、通常pstopなどの状態Dに表示されます。

1
derobert

はい、IOを待っているタスクはブロックされ、他のタスクが実行されます。次のタスクの選択は Linuxスケジューラー によって行われます。

0

通常、プロセスはブロックされます。読み取り操作が非ブロッキングとしてマークされたファイル記述子に対して行われる場合、またはプロセスが非同期IOを使用している場合、ブロックされません。また、ブロックされていない他のスレッドがある場合実行を継続できます。

次に実行するプロセスに関する決定は、カーネル内の scheduler までです。

0
Benno