Linux -> スレッドの基本概念

目次

序文:

1. スレッドの基本概念

2 スレッドの利点

3 スレッドのデメリット

4 データブロックサイズが4KBである本当の理由


序文:

        この記事では、スレッドとプロセスの違いと関係、スレッドの長所と短所、メモリデータ管理とディスクの関係、仮想メモリとメモリの対応付け方法、ページテーブルの補足知識などを解説します。

1. スレッドの基本概念

        スレッドを学ぶ前に、まず概念を紹介します。

1. スレッドは、プロセスよりも実行粒度が細かく、スケジューリング コストが低い実行ブランチです。

2. スレッドはプロセス内の実行フローです。

3. スレッドは CPU スケジューリングの基本単位であり、プロセスはリソース割り当てを担当するエンティティです。

        まず、単一の実行フローの図を示します。

 

        上の図は、プロセスがどのように機能を実行するかを示しています。CPU はこのプロセスをスケジュールし、PCB を通じて仮想メモリを見つけ、次に仮想メモリとページ テーブルを通じてデータが保存されている実際の物理メモリの場所を見つけます。では、概念1、スレッドは実行ブランチであり、実行粒度はプロセスよりも低いですが、どのように理解すればよいでしょうか。

        各プロセスは独自のアドレス空間、メモリ、その他のリソースなどを持っています。これについては疑いの余地がありません。各プロセスは互いに独立した独自の独立したメカニズムのセットを持っています。これが私たちが学んだことですが、スレッド以下の図に示すように、プロセス内で実行され、複数のスレッドが同じプロセスのリソースを共有できます。

         つまり、同じアドレス空間が複数の PCB から見えますが、これはプロセスでは実現できない部分です。そこで今回の疑問ですが、スレッドの管理や編成はどのように実現されているのでしょうか?それを走り回らせるのは不可能です。もちろん、それは不可能です。実際、Linux では、スレッド管理メソッドはプロセス PCB ソリューションに含まれており、本質的にはそれらはほぼ同じであり、実行フローの場所と内容を記述するために使用されます。ただし、スレッドには独自のアドレス空間とページ テーブルがないため、スレッドの管理も PCB と同じであり、このようなスレッド PCB を LWP 軽量プロセスと呼びます。

        では、スレッドを実行ブランチとしてどのように理解すべきでしょうか? 実際、異なるスレッド PCB はすべて同じアドレス空間を参照するため、このアドレス空間の異なる部分を個別に実行できます。シリアルにのみ実行できる元の単一実行フロー プロセスとは異なり、複数の実行フローは同じコピーを同時に実行できます。コードこの部分については、後で皆さんにお見せするためにコードを添付します。

        では、スレッド スケジューリングのコストを下げるにはどうすればよいでしょうか?

        まず、プロセスを学習しているときに、プロセスが置き換えられると、CPU は新しい PCB の値を読み取り、レジスターの値を置き換え、それに応じてアドレス空間も変更されると述べましたただし、これらの条件だけでは、スレッドのスケジューリング コストが低いという概念を反映していません。レジスタの値を置き換える場合でも、アドレス空間を置き換える場合でも、ページ テーブルはポインターを置き換えているだけであり、スケジューリング コストは削減されないからです。実際に削減される部分は、実際には CPU 内のキャッシュの内容です。私たちのコンピューターは実行時に局所性の原則に従っていること、つまり、特定のコード部分を実行すると、オペレーティング システムがそのコード部分を保存することがわかっています。コードのこの部分はアクセスされる可能性が高いため、周囲のコードも読み込まれます。では、プロセスの置き換えであれば何も言うことはなく、徐々にchcheの内容を置き換えていくしかありませんが、スレッドの場合はどうなるでしょうか?同じリソースが見えるため、キャッシュ内のコンテンツを置き換える必要がない可能性が高く、実際のスケジューリング コストが削減されます

         最初の概念の説明は誰もが理解していると思いますが、2 番目の概念はどのように理解すればよいでしょうか? スレッドはプロセス内の実行の流れです。これまでの理解では、スレッドには独自の PCB があることがすでにわかっていますが、なぜそれがプロセス内の実行フローであると言えるのでしょうか? この問題は非常に単純です。実際、スレッドだけではプログラムを実行できません。スレッドは独自のアドレス空間を持たず、プロセスのアドレス空間を使用するためです。つまり、私たちが目にするプロセスは次のようになります。形:

         スレッドの実行はプロセスに基づいているため、3 番目の概念が導入されます。スレッドは CPU の基本的なスケジューリング単位であり、プロセスはリソース割り当てを担当するエンティティの概念です。

        私たちが知っているプロセスは CPU の基本的なスケジューリング単位であることがわかりますが、これは実際には不完全な概念です。当時、プロセスには実行フローという概念が 1 つしかないことしか知らなかったため、次のように考えるのが簡単です。プロセスは CPU の基本的なスケジューリング単位ですが、スレッドの導入後、不足していた知識が追加されました。

#include<pthread.h>
#include<iostream>
#include<unistd.h>

using namespace std;

void* task1(void* x)
{
    while(true)
    {
        sleep(1);
        cout << "我是线程1, 正死循环当中" << endl;
        
    }
}

void* task2(void* x)
{
    while(true)
    {
        sleep(1);
        cout << "我是线程2, 正死循环当中" << endl;
        
    }
}

int main()
{
    pthread_t t1,t2;

    pthread_create(&t1,nullptr,task1,nullptr);
    pthread_create(&t2,nullptr,task2,nullptr);

    while(true)
    {
        sleep(1);
        cout << "我是主线程, 正死循环当中" << endl;
        
    }
    return 0;
}

         OS は LWP によってスレッドを区別し、同じ LWP と PID がメイン スレッドであり、OS は PID と LWP を使用してデータを再ロードするか、データを置き換えるかどうかを決定します。

2 スレッドの利点

1. 新しいスレッドを作成するコストは、新しいプロセスを作成するよりもはるかに小さくなります。
2. プロセス間の切り替えと比較して、スレッド間の切り替えに必要なオペレーティング システムの作業ははるかに少なくなります。
3. スレッドが使用するリソースはプロセスよりもはるかに少ない
4. 並列プロセッサ数を最大限に活用できる
5. 遅い I/O 操作が終了するのを待っている間、プログラムは他のコンピューティング タスクを実行できます。
6. コンピューティング集約型アプリケーションの場合、マルチプロセッサ システムで実行するために、計算は実装のために複数のスレッドに分解されます。
7. I/O 集中型のアプリケーションは、パフォーマンスを向上させるために、 I/O 操作をオーバーラップさせます。 スレッドは、さまざまなI/O 操作を同時に待機できます。

         スレッド自体は、プロセスのように対応するアドレス空間やその他のデータを作成するのではなく、PCB を構築するだけでよいため、そのコストはプロセスよりも低くなければならず、スレッドを切り替えるときに、OS はこの PCB とスレッドの違いを認識します。同じプロセスに属することで、多くの置換操作が削減され、スレッドはアドレス空間を格納するために追加の領域を開く必要がないため、消費されるリソースはプロセスよりも小さくなります。プロセスには複数のスレッドがあり、CPU はマルチコア プロセッサであるため、プロセスはこれらのプロセッサを最大限に活用できます。

        5 番目のポイントについては、実際にビデオをダウンロードする際のダウンロードと視聴の操作を例に挙げます。ダウンロードと視聴は 2 つの実行ストリームに属している必要があり、スレッドは同じアドレス空間を直接共有できるため、側で見られる操作は以下は実装が非常に簡単です。ただし、あるプロセスがダウンロードし、ダウンロードしたデータをプロセス間通信を通じてビデオを視聴する別のプロセスに転送するため、これはプロセス間でも実現できるため、この利点は明らかではありません。

        6 点目と 7 点目については、実際には 1 つの実行フローを複数の実行フローに分割し、同じプログラムを並行して実行し、演算の完了時間を高速化することであり、CPU がタイムスライスを介して PCB を切り替えることがわかっています。プロセスはあります。 PCB の数が増えると、実行に時間がかかり、当然その分完成速度も上がります。ただし、注意が必要なのは、コンピュータ自体のコアが数個しかない場合、スレッドをいくら開いても、実際に実行できるスレッドはその数個だけであるため、あまり多くのスレッドを開く必要はありません。 、スレッドが多すぎると、スケジューリング コストの増加が発生します。スレッドのスケジューリング コストは低くなりますが、そのようなことがないわけではありません。

3 スレッドのデメリット

パフォーマンスのペナルティ:外部イベントによってめったにブロックされない計算集約型のスレッドは、多くの場合、同じプロセッサを他のスレッドと共有できません。計算負荷の高いスレッドの数が利用可能なプロセッサよりも大きい場合、大幅なパフォーマンスの損失が発生する可能性があります。ここでのパフォーマンスの損失とは、利用可能なリソースが変化しないまま、追加の同期とスケジューリングのオーバーヘッドが追加されることを指します。
堅牢性の低下:マルチスレッドの記述には、より包括的かつ詳細な検討が必要です。マルチスレッド プログラムでは、時間配分のわずかなずれや、共有すべきでない変数の共有によって悪影響が生じる可能性が高くなります。スレッド間の保護。
アクセス制御の欠如:プロセスはアクセス制御の基本的な粒度であり、スレッド内で特定の OS 関数を呼び出すと プロセス全体に影響します。
プログラミングの難易度の上昇:マルチスレッド プログラムの作成とデバッグは、シングルスレッド プログラムよりもはるかに困難です。

         パフォーマンスの低下は、実際にはスレッドのポイントで述べたとおりであり、オープンされるスレッドの数が適切でないと、最終的にはスケジューリング コストの増加につながります。

        スレッドの堅牢性の低下は実際にはスレッド実行エラーであり、スレッドはプロセスに属し、スレッドのエラーはプロセスのエラーであり、異常なシグナルであるため、プロセス全体の崩壊につながります。スレッドによって引き起こされる信号は、実際にはプロセスの異常信号です。

        アクセス制御ができないことについては今すぐ説明することはできませんが、これにはアトミック性の問題が関係しますので、次の記事で説明します。そして最後の点は、実際には人によって異なります。マルチスレッド プログラミングに精通している人もいれば、マルチプロセス プログラミングを好む人もいるからです。

4 データブロックサイズが4KBである本当の理由

        データ ブロックが何なのかさえ知らない友人がいる場合は、ディスク ファイル管理の関連コンテンツに目を向けることができます。しかし、それでも思い出させておきます。

        まず、ディスクの各セクターは 512 バイトのスペースがありますが、OS がコンテンツのこの部分を読み取るとき、このサイズの 8 セクター (4KB) を連続して読み取ります。4KB のデータはデータ ブロックです。

        データ ブロックが存在する理由は、ディスクにデータを書き込む場合、100 回の IO 操作を実行した方が良いのか、それともデータがロードされた後に 1 回データを書き込む方が良いのかからです。もちろん、IO 動作はメモリとペリフェラル間のやり取りなので、書き込みは一度に完了する方が良いですが、その速度は非常に遅くなければなりませんので、そのような動作はできるだけ避ける方が良いです。これはデータブロックが出現する意味でもあり、1バイトのコンテンツを書き込むたびにIOが行われるのであれば、そのディスクは本当に強力であるとしか言いようがありません。現在のコンピュータのニーズを満たせるのであれば、このディスクでスイートを購入できます。

        そして、この4KBのサイズは、ディスクに保存する時点ですでに計画されており、OSの読み込みは4KBのサイズと規定されており、今後ディスクから検索する際には、該当する4KBのデータを直接見つけてまとめてメモリにロードすることになります。

        そこで質問なのですが、必要なデータが 1 バイトだけの場合、4KB のコンテンツもロードされるのでしょうか? これを行うとデータへのアクセス速度が遅くなりませんか? この質問は問題ありませんが、コンピュータは局所性の原則に基づいていますが、これは何を意味しますか? つまり、ユーザーがこのデータにアクセスしたとコンピューターが予測した場合、このバイト付近のデータにアクセスする可能性が高く、データのこの部分も一緒にロードされます。これにより、データの再検索が高速化されるのではなく、再検索が高速化されます。 1 回の検索での速度比較。

        そのため、ディスクやメモリの場合、連続した物理アドレスのように見えても、実際にはデータは断片的に管理されます。そして、そのようなデータブロックには対応する管理方法、つまり空きページフレームリンクリストが必要であり、特定の空き位置を見つけて、そこにデータブロックを配置する必要があります。

        上記の内容では、データ ブロックをデータに追加する理由は明確に説明されていますが、なぜ 4KB なのかについては説明されていないため、この部分については仮想アドレスから理解する必要があります。

        アドレス空間を学習しているときに疑問に思うことがありますか。つまり、仮想アドレスには 4GB の空間があるということです。極端な条件下では、ページ テーブル エントリのサイズが 12 バイトしかないと仮定すると、2^32*12 は 48GB に相当します。サイズは、ページテーブルは 48G です。これは冗談ではありません。彼がそれを保存できるような大きな場所がどこにあるでしょうか。これは無理があると思いますが、32 ビット マシンのアドレスは 4 バイト、つまり 32 ビットであることに注意してください。それを 10+10+12 に分割します。これはどういう意味ですか? 最初の 10 ビットは検索に使用されます。第 1 レベルのページ テーブル内の第 2 レベルのページ テーブル。中央の 10 ビットは、メモリ内のデータ ブロックの開始位置を見つけるために使用されます。最後の 12 ビットはどうなりますか? 2^12 とは何かを計算してみましょう。4KB の場合、この 4KB にデータ ブロックのベース アドレスを加えた値を使用して、データ ブロック内のバイトを検索します。これが 4KB サイズの最終的な理由です

        写真が示すように:

         このようにアドレスを分割した後のページ テーブルのサイズは、極端な条件下でも最大でも 2^20*12、つまり数 MB になりますが、メモリに格納できますか? 非常に簡単で、通常の状況ではページテーブルがこの条件を満たすことは不可能であるため、一般的なページテーブルは数KB程度であり、ページテーブルが大きすぎる問題を解決することに成功しました。

        また、プロセスはロード時にすべてのデータをメモリにロードするのではなく、部分ごとにロードすることもわかっており、その場合、必然的に特定のデータ ブロックがページ テーブルで見つからない可能性があるという問題が発生します。ページ フォールト割り込みの問題が発生すると、OS がディスクに移動してこのデータ ブロックを見つけ、メモリにロードして、プログラム全体が実行を継続します。

        ページテーブルには仮想アドレスと物理アドレスだけでなく、ヒットの有無、読み取り、書き込み、実行の権限、およびユーザーのカーネル権限の違いもあります。このようにして、仮想アドレスから物理メモリへの変換中にコードが権限を超えているかどうかを知ることができます。

        例として:

char* s = "ハローワールド";

*s = 'H';

         このコードは実行中に必ずセグメント エラーが発生しますが、どうやってそれを見つけたのでしょうか?

        まず、 s がアドレスを指している必要があることがわかっており、そのアドレスはページ テーブルを通じて実際の物理メモリを見つけ、物理アドレスへの仮想アドレスはハードウェア MMU によって実現されます。一定領域のデータを変更している場合、不正な操作があった場合、エラーが報告され、OS が MMU エラーを認識し、対応するプロセスにセグメント障害信号を送信し、プロセスが信号を受信します。この信号の処理方法はプログラムをクラッシュさせるため、プログラムの実行中にワイルド ポインタの問題がクラッシュの原因となることがわかります


        上記はこの部分の知識について私が完全に理解したものであり、皆様のお役に立てば幸いです。

おすすめ

転載: blog.csdn.net/weixin_52345097/article/details/131246075