【再掲】プロセスとスレッドの違い(OSレベルでわかる)

1. プロセスとは何ですか? なぜプロセスがあるのでしょうか?

プロセスについては、かなり簡潔に説明します。プロセスとは、オペレーティング システム上で実行されるプログラムを抽象化したものです。

この概念は確かに非常に抽象的ですが、よく考えてみると非常に正確です。

私たちが通常コンピュータを使用するとき、映画を見たり、WeChat でチャットしたり、ブラウザの Baidu を開いて検索したりするなど、多くのことを同時に行っていますが、私たちが行っている多くのことの背後では、ソフトウェア プログラムが実行されています。 , まずディスク上に独自のプログラム コードを用意し、次にそのコードをメモリにロードする必要があります。CPU がコードを実行します。動作中に、保存する必要のある大量のデータが生成され、また必要な場合もあります。ネットワーク カード、グラフィック カード、およびキーボードと組み合わせることができます。外部デバイスが相互作用するとき、これには実際にはプログラムによるコンピュータ リソースの使用が含まれます。非常に多くのプログラムがあるため、当然、プログラム リソースの使用を管理する方法を見つける必要があります。また、CPU が 1 つしかない場合、オペレーティング システムは、ユーザー エクスペリエンスに影響を与えることなくこれらのプログラムが同時に実行されているように感じられるように、CPU をさまざまなプログラムに割り当てるようにスケジュールする必要があります。

もちろん、オペレーティング システムは、実行中の各プログラムを独立したエンティティにカプセル化し、それぞれに必要なリソースを割り当て、スケジューリング アルゴリズムに従って実行を切り替えますこの抽象的なプログラム実体がプロセスです。

したがって、プロセスに関する公式の説明の多くは次のように述べています。プロセスは、オペレーティング システムによるリソースの割り当てとスケジューリングの基本単位です

2. スレッドとは何ですか? なぜスレッドがあるのでしょうか?

初期のオペレーティング システムにはスレッドの概念がありませんでした。プロセスとは、リソースを持ち、独立して実行できる最小単位であり、プログラム実行の最小単位でもあります。タスクスケジューリングはタイムスライスローテーション方式のプリエンプティブスケジューリング方式を採用しており、タスクスケジューリングの最小単位はプロセスであり、各プロセスは独立したメモリ空間を持ち、各プロセスのメモリアドレスは互いに分離されています。

その後、コンピューター産業の発展に伴い、プログラムの機能設計はますます複雑になり、アプリケーション内で複数のアクティビティが同時に発生し、ネットワーク リクエスト、ファイルの読み取りと書き込みなど、時間の経過とともに一部のアクティビティがブロックされるようになりました。 、IO 操作など)、これらのアプリケーションをより細かい粒度に分解できるかどうか、複数の順次実行エンティティを並行して実行できるかどうか、そしてこれらの粒度の細かい実行エンティティがプロセスのアドレス空間を共有できるかどうか、つまり、プログラムコード、データ、メモリ空間などを共有することで、プログラミングモデルがよりシンプルになります。

実際、コンピューターの世界における多くの技術開発は現実世界をシミュレートしています。例えば、プロセスをプロジェクトと捉えますが、プロジェクトのタスクが複雑になった場合、事業、製品、作業の方向性などに応じてプロジェクトをタスクモジュールに分割し、担当者に割り当てることができないかということを当然考えます。並行して完了し、何らかの方法でそれぞれのタスクの結果を整理し、最終的にプロジェクトを完了します。

マルチスレッドが必要なもう 1 つの重要な理由は、各プロセスが独立したコードとデータ空間 (プログラム コンテキスト) を持ち、プログラム間の切り替えには大きなオーバーヘッドが発生することです。スレッドは軽量プロセスと見なすことができ、同じクラスのスレッドは共有されます。コードとデータ空間 各スレッドには独自の独立した実行スタックとプログラム カウンタがあり、スレッド間の切り替えのオーバーヘッドは小さいです。したがって、スレッドの作成、破棄、およびスケジュールのパフォーマンスは、プロセスのパフォーマンスよりもはるかに優れています

マルチスレッド モデルの導入後、プログラム実行中のプロセスとスレッド間の分業は非常に明確になり、プロセスはシステム リソースの割り当てと管理を担当し、スレッドは CPU のスケジューリング操作を担当し、 CPUスイッチングタイムスライスの最小単位。どのプロセスでも、スレッドを積極的に作成しなくても、プロセスにはデフォルトでメインスレッドがあります。

3. Linux カーネルでの実装方法はどのように異なりますか?

Linuxでは、プロセスであってもスレッドであっても、カーネル内ではタスク(Task)と呼ばれ統一された構造でtask_struct 管理されていますが、このデータ構造は非常にtask_struct複雑であり、プロセス管理のライフサイクルにおける様々な情報が含まれています。
ここに画像の説明を挿入
最初のプロセスは、Linux オペレーティング システムのカーネルが初期化されるときに作成されます0号创始进程次に、プロセス 1 (ユーザー プロセスの先祖: /usr/lib/systemd/systemd) とプロセス 2 (カーネル プロセスの先祖: [kthreadd]) が初期化され、それらに基づいて後続のすべてのプロセス スレッドがフォークされます。

#ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0  2022 ?        05:05:39 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root          2      0  0  2022 ?        00:00:07 [kthreadd]
root          3      2  0  2022 ?        00:00:00 [rcu_gp]
root          4      2  0  2022 ?        00:00:00 [rcu_par_gp]
root          6      2  0  2022 ?        00:00:00 [kworker/0:0H-ev]
root          8      2  0  2022 ?        00:00:00 [mm_percpu_wq]
root          9      2  0  2022 ?        00:00:00 [rcu_tasks_rude_]
root         10      2  0  2022 ?        00:00:00 [rcu_tasks_trace]
root         11      2  0  2022 ?        00:01:43 [ksoftirqd/0]

ここに画像の説明を挿入
通常、fork新しいプロセスはシステム コールを通じて作成されます。fork システム コールには 2 つの重要なイベントが含まれています。1 つは、task_struct 構造体をコピーして初期化すること、もう 1 つは、新しく作成された子プロセスを起動しようとすることです。

プロセスもスレッドもカーネル内ではすべてタスクと言われますが、それらは同じように管理されているのではないでしょうか?違いをどうやって見分けるのでしょうか?実際、スレッド化はカーネルによって完全に実装されるメカニズムではなく、カーネル モードとユーザー モードの連携によって完成されます
https://www.ixigua.com/6972128479705825829
プロセスを作成するときに呼び出されるシステムコールは fork で、これ以降、 files_structfs_structsighand_structsignal_struct、の 5 つの主要な構造mm_structがコピーされ、それ以降、親プロセスと子プロセスがそれぞれ独自のデータ構造を使用します。スレッドを作成する際にはシステムコール clone が呼び出されますが、主な構造は参照カウントに 1 を加えた 5 つの構造であり、これがスレッド共有処理のデータ構造です。
ここに画像の説明を挿入

4. プロセスとスレッドの違いを要約しますか?

機能: プロセスはオペレーティング システムのリソース割り当ての基本単位であり、スレッドはタスクのスケジューリングと実行の基本単位です。

オーバーヘッド: 各プロセスには、コードやデータ セグメントなどを保存するための独立したメモリ空間があります。プログラム間の切り替えには大きなオーバーヘッドが発生します。スレッドはメモリ空間を共有する軽量プロセスとみなすことができ、各スレッドには独自の独立した実行スタックがあります。とプログラムカウンタを備えており、スレッド間の切り替えのオーバーヘッドは小さいです。

実行環境:オペレーティングシステムでは複数のプロセスを同時に実行でき、同じプロセス(プログラム)内で複数のスレッドが同時に実行されます(CPUスケジューリングにより、各タイムスライスで1つのスレッドのみが実行されます)。

プロセスの作成: 新しいプロセスを作成するとき、親プロセスの 5 つのデータ構造すべてがコピーされて、独自の新しいメモリ空間データを形成します。新しいスレッドを作成するとき、プロセスの 5 つのデータ構造が参照されます。ただし、スレッドは独自のプライベートデータとスタックスペースを持っています。

実際、プロセスとスレッドは、CPU の観点からは task_struct 構造体にカプセル化されています。これらはさまざまなタスクを実行できます。さらに、CPU の観点からは、これらのタスクを実行するときに、対応するスケジューリング戦略とコンテキスト リソースの切り替え定義に従います。 、レジスタ アドレスの切り替え、カーネル スタックの切り替えを含みます。したがって、CPU の場合、プロセスとスレッドの間に違いはありません。

添付ファイル: コンテキスト切り替えとは何を意味しますか?

オペレーティング システムはプロセスの概念を抽象化し、アプリケーションが独自のビジネス ロジックの実装に集中できるようにします。CPU スケジューリングやメモリ管理などのハードウェアの詳細からアプリケーションを保護し、限られた CPU で多くのタスクを「同時に」実行できます。ただし、ユーザーに利便性をもたらす一方で、追加のオーバーヘッドも発生します。

オペレーティング システムでは、CPU のタイム スライス スケジューリング ポリシーにより、あるプロセスから別のプロセスに切り替えるには、現在のプロセスの状態を保存し、他のプロセスの状態を復元する必要があります。つまり、現在実行中のタスクが準備完了 (または一時停止) に変わります。 、削除済み) 状態、別の選択された準備完了タスクが現在のタスクになります。コンテキストの切り替えには、現在のタスクの実行環境の保存と、実行するタスクの実行環境の復元が含まれます。

コンテキスト切り替えプロセス中、CPU は現在実行中のプログラムの処理を停止し、後で実行を継続できるように現在のプログラムの特定の場所を保存します。この観点から見ると、コンテキストの切り替えは、私たちが複数の本を同時に読んでいるのと似ており、本を前後に切り替えながら、各本の現在のページ番号を覚えておく必要があります。

コンテキストの切り替えは、割り込み処理、マルチタスク、カーネル/ユーザー モードの切り替えの3 つの状況で発生する可能性があります。

割り込み処理では、他のプログラムが現在実行中のプログラムに「割り込み」ます。CPU は割り込み要求を受信すると、実行中のプログラムと割り込み要求を開始したプログラムの間でコンテキストの切り替えを実行します。

マルチタスクでは、CPU は異なるプログラム間を行き来し、各プログラムには対応する処理タイム スライスがあり、CPU は 2 つのタイム スライスの間でコンテキスト スイッチングを実行します。

Linux でのカーネル/ユーザー モードの切り替えもコンテキストの切り替えを引き起こすため、システム コールを実行するときは、最初に CPU レジスタ内の元のユーザー モード命令の場所を保存する必要があります。次に、カーネル モード コードを実行するには、CPU レジスタをカーネル モード命令の新しい位置で更新する必要があります。最後に、カーネル状態にジャンプして、カーネル タスクを実行します。システムコール終了後、CPU レジスタは最初に保存されたユーザー状態を復元し、プロセスの実行を継続するためにユーザー空間に切り替える必要があるため、システムコール中に実際には 2 つの CPU コンテキストスイッチが発生します。

CPU コンテキスト スイッチングは、Linux システムの正常な動作を保証するためのコア機能の 1 つであり、通常は特別な注意を払う必要はありません。

ただし、過度のコンテキスト切り替えは、レジスタ、カーネル スタック、仮想メモリなどのデータの保存と復元に CPU 時間を消費するため、プロセスの実際の実行時間が短縮され、システム全体のパフォーマンスが大幅に低下します。

元のリンク: https://blog.csdn.net/qq_40989769/article/details/129047723

おすすめ

転載: blog.csdn.net/yuelai_217/article/details/130198483