オペレーティングシステムの定型的なエッセイを 1 日で理解する

オペレーティング システムの 4 つの特徴?

並行性: 同じ時間内に複数のプログラムを実行する (並列性とは異なり、並列性は同時に複数のイベントを指す。マルチプロセッサ システムではプログラムを並列に実行することができる)

共有: システム内のリソースは、メモリ内で同時に実行される複数のスレッドで共有できます。

仮想: 物理エンティティを複数に仮想化する

非同期: システム プロセスはストップ アンド ゴー方式で (一度にすべてではなく) 実行され、プロセスがいつ、どのくらいの速さで前進するかは予測できません。

プロセススレッド

プロセスとは、メモリ内で実行されるアプリケーション プログラムを指し、各プロセスには独自の独立したメモリ空間があります。

スレッドはプロセスより小さい実行単位です. プロセス内の独立した制御フローです. プロセスは複数のスレッドを開始できます. 各スレッドは異なるタスクを並行して実行します.

プロセスとスレッドの違いは次のとおりです

  • スケジューリング: プロセスはリソース管理の基本単位であり、スレッドはプログラム実行の基本単位です。
  • 切り替え: スレッド コンテキストの切り替えは、プロセス コンテキストの切り替えよりもはるかに高速です。
  • リソースの所有: プロセスは、リソースを所有する独立した単位です。スレッドはシステム リソースを所有しませんが、プロセスに属するリソースにアクセスできます。
  • システム オーバーヘッド: プロセスを作成またはキャンセルする場合、システムはメモリ空間、I/O デバイスなどのシステム リソースを割り当てるか、再利用する必要があります。OS によって支払われるオーバーヘッドは、スレッドを作成またはキャンセルするときのオーバーヘッドよりも大幅に大きくなります。 、およびプロセス切り替えのオーバーヘッドも、スレッド切り替えのオーバーヘッドよりもはるかに大きくなります。

この記事は Github ウェアハウスに含まれており、コンピューター基盤、Java 基盤、マルチスレッド化、JVM、データベース、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分散型、マイクロサービス、デザイン パターン、アーキテクチャ、学校の募集、社会的募集の共有が含まれています。などコア知識ポイント、スターへようこそ〜

Githubアドレス

Github にアクセスできない場合は、gitee のアドレスにアクセスできます。

ジーティーアドレス

並行性と並列性

同時実行性とは、一定期間内に複数のタスクが処理されることを意味しますが、ある瞬間に実行されるタスクは 1 つだけです。シングルコア プロセッサは同時実行できます。たとえば、Aと の2 つのプロセスがありBAタイム スライスの実行後に に切り替えBBタイム スライスの実行後に に切り替えますAスイッチング速度が十分に速いため、複数のプログラムを一定期間同時に実行できることが巨視的に示されます。最も包括的な Java インタビュー サイト

並列処理とは、複数のタスクが同時に実行されることを意味します。これにはマルチコア プロセッサが必要です. マイクロ レベルでは、複数の命令を同時に実行できます. 異なるプログラムが異なるプロセッサで実行されます. これは物理的に同時に複数のプロセスです.

シングルスレッドに対するマルチスレッドの利点

1. 並行性はプログラムの実行効率を向上させます

2. CPU 使用率を改善し、メモリにアクセスするときに実行するスレッドを切り替えることができます

3.応答速度が速くなり、ユーザーリクエストを監視する専用スレッドとリクエストを処理する専用スレッドを持つことができます。たとえば、リスニング スレッドとワーキング スレッドは 2 つのスレッドであり、リスニング スレッドが監視を担当し、ワーカーが作業を担当し、ユーザー リクエストが検出されると、リクエストは即座にワーキング スレッドに転送されて処理されます。 、リッスン スレッドは引き続き監視します。

コルーチンとは何ですか?

コルーチンは、ユーザー モードの軽量スレッドです。

コルーチンはオペレーティング システムのカーネルによって管理されるのではなく、ユーザー プログラムによって完全に制御されるため、パフォーマンスが大幅に向上し、スレッドの切り替えなどのリソースを消費しないという利点があります。

コルーチンは、実行を一時停止できる関数として理解できます。独自のレジスタ コンテキストとスタックがあります。コルーチン スケジュールが切り替わると、レジスタ コンテキストとスタックが別の場所に保存されます. 元に戻すと、以前に保存されたレジスタ コンテキストとスタックが復元されます. スタックの直接操作のためのカーネル切り替えオーバーヘッドは基本的にありません.ロックせずにアクセスできるため、コンテキストの切り替えは非常に高速です。

スレッドとコルーチンの違いは何ですか?

1. スレッドはプリエンプティブですが、コルーチンは非プリエンプティブであるため、他のコルーチンに切り替えるには、ユーザーが使用権を解放する必要があります.したがって、同時に実行できるコルーチンは 1 つだけです。単一のスレッド。
2. スレッドはコルーチンのリソースです。コルーチンは、任意のスレッドまたはスレッド プールに関連付けることができるエグゼキューター (インターセプター) を介して間接的にスレッド リソースを使用します。

プロセス通信

プロセス間で通信するには、いくつかの方法があります。

1.パイプライン通信

匿名パイプ ( pipe ): パイプは半二重通信方式であり、データは一方向にしか流れず、親族関係のあるプロセス間でのみ使用できます。プロセス アフィニティは通常、プロセスの親子関係を指します。
ウェルノウン パイプは半二重通信方式であり、データは一方向にしか流れません。

2.メッセージキュー

3.共有メモリ共有メモリは、IPC の最速の方法であり、プロセス間通信の他の方法を実行すると非効率的に実行されるように特別に設計されています。多くの場合、プロセス間の同期と通信を実現するために、セマフォなどの他の通信メカニズムと組み合わせて使用​​されます。

4.セマフォセマフォは、複数のプロセスによる共有リソースへのアクセスを制御するために使用できるカウンターです。あるプロセスがリソースにアクセスしている間、他のプロセスが共有リソースにアクセスできないようにするためのロック メカニズムとしてよく使用されます。したがって、主にプロセス間および同じプロセス内の異なるスレッド間の同期の手段として使用されます。

デッドロックとは?

デッドロックとは、実行中のリソースの競合により、2 つ以上のスレッドが互いに待機する現象を指します。外力がなければ、前進することはできません。

下図のように、スレッド A はリソース 2 を保持し、スレッド B はリソース 1 を保持しています。両者は同時に相手が保持しているリソースを申請したいので、2 つのスレッドはお互いに待機し、リソース 1 に入ります。デッドロック状態。

[外部リンクの画像転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (img-E8WXcqiK-1681546229546)(http://img.topjavaer.cn/img/デッドロック.png)]

次の例は、スレッドのデッドロックを示しており、コードは並行プログラミングの美しさから生まれています。

最後に、 C 言語、C++、Java、Python、フロントエンド、データベース、オペレーティング システム、コンピューター ネットワーク、データ構造など、 Dabin によってコンパイルされた300 以上の古典的なコンピューター ブックの PDF を含むGithub ウェアハウスを共有したいと思います。とアルゴリズム、機械学習、プログラミング生活など、あなたはそれに星を付けることができます、次に本を探すときは直接検索してください、倉庫は継続的に更新されています〜

Githubアドレス

public class DeadLockDemo {
    
    
    private static Object resource1 = new Object();//资源 1
    private static Object resource2 = new Object();//资源 2

    public static void main(String[] args) {
    
    
        new Thread(() -> {
    
    
            synchronized (resource1) {
    
    
                System.out.println(Thread.currentThread() + "get resource1");
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
    
    
                    System.out.println(Thread.currentThread() + "get resource2");
                }
            }
        }, "线程 1").start();

        new Thread(() -> {
    
    
            synchronized (resource2) {
    
    
                System.out.println(Thread.currentThread() + "get resource2");
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource1");
                synchronized (resource1) {
    
    
                    System.out.println(Thread.currentThread() + "get resource1");
                }
            }
        }, "线程 2").start();
    }
}

コード出力は次のとおりです。

Thread[线程 1,5,main]get resource1
Thread[线程 2,5,main]get resource2
Thread[线程 1,5,main]waiting get resource2
Thread[线程 2,5,main]waiting get resource1

synchronizedスレッド A は、(resource1)を介して resource1 のモニター ロックを取得し、 を渡しますThread.sleep(1000)スレッド B を実行できるようにスレッド A を 1 秒間スリープさせてから、resource2 の監視ロックを取得します。スレッド A とスレッド B のスリープが終了した後、両方が相手のリソースを要求し始め、その後、2 つのスレッドが互いに待ち合わせ状態に陥り、デッドロックが発生します。

デッドロックはどのように発生しますか? それを避ける方法は?

デッドロックが発生するための 4 つの必要条件:

  • 相互排除: リソースは、一度に 1 つのプロセスでのみ使用できます

  • 要求と保留: リソースの要求によってプロセスがブロックされた場合、取得したリソースは解放されません

  • 剥奪なし: プロセスによって取得されたリソースは、使用される前に強制的に剥奪することはできません

  • 循環待機: プロセス間で周期的にリソースを待機する

デッドロックを回避する方法:

  • ロックは相互排除を保証するため、相互排除条件を破棄することはできません
  • 一度にすべてのリソースに適用し、スレッドがリソースを占有して他のリソースを待機することを回避します
  • 一部のリソースを占有しているスレッドがさらに別のリソースを申請する場合、アプリケーションが取得できない場合は、占有しているリソースを積極的に解放します
  • リソースを順番に申請する

プロセスのスケジューリング戦略とは?

  • 先着順: 非プリエンプティブ スケジューリング アルゴリズム、リクエストの順序に従ってスケジューリングします。長いジョブには適していますが、短いジョブには適していません。短いジョブは、前の長いジョブが実行されるまで待機する必要があり、長いジョブは長時間実行する必要があるため、短い仕事の待ち時間が長すぎる。さらに、I/O集中的なプロセスには適していません。そのようなプロセスは、I/O各操作の後に再キューイングする必要があるためです。

  • Shortest job first : 推定実行時間が最短の順序でスケジュールする非プリエンプティブ スケジューリング アルゴリズム。長いジョブは枯渇する可能性があり、短いジョブが終了するのを待っている状態になります。短いジョブが来続ければ、長いジョブはスケジュールされないからです。

  • Shortest Remaining Time First : Shortest Job First のプリエンプティブ バージョンで、残りの実行時間の順にスケジュールされます。新しいジョブが到着すると、その全体の実行時間が現在のプロセスの残り時間と比較されます。新しいプロセスに必要な時間が短い場合は、現在のプロセスを中断して、新しいプロセスを実行します。それ以外の場合、新しいプロセスは待機します。

  • タイム スライス ローテーション: の原則FCFSに従ってCPU、スケジュールされるたびにキュー リーダー プロセスに時間を割り当てます。このプロセスはタイム スライスを実行できます。タイム スライスが使い果たされると、タイマーはクロック割り込みを送信し、スケジューラはプロセスの実行を停止してレディ キューの最後に送信しますが、キューの先頭にあるプロセスにCPU時間を

    タイム スライス ローテーション アルゴリズムの効率は、タイム スライスのサイズに大きく関係します。プロセスの切り替えでは、プロセス情報を保存し、新しいプロセスの情報をロードする必要があるため、タイム スライスが小さすぎると、プロセスの切り替えが失敗します。頻繁すぎる.時間がかかりすぎる. また、タイム スライスが長すぎると、リアルタイムのパフォーマンスが保証されません。

  • 優先度スケジューリング:各工程に優先度をつけ、優先度に従ってスケジュールします。優先度の低いプロセスがスケジュールされるのを決して待機しないようにするために、待機中のプロセスの優先度を徐々に上げることができます。

プロセスの状態とは?

プロセスには、作成、準備完了、実行中 (実行)、終了、およびブロックの合計53 つの。

  • 実行中の状態は、プロセスがCPU実行されていることです。ユニプロセッサー環境では、一度に多くても 1 つのプロセスが実行されます。
  • 準備完了状態は、プロセスがすでに実行可能な状態にあることを意味します。つまり、プロセスは、CPUリソースを除くすべての必要なリソースを取得しており、CPU取得したら実行できます。
  • ブロック状態とは、リソースが使用可能になるか完了するのを待機するなど、イベントを待機している間にプロセスが中断されることですI/Oアイドル状態であってもCPU、プロセスは実行できません。

実行状態→ブロッキング状態: 周辺機器待ち、メインメモリなどのリソース割り当て待ち、手動介入待ちなどが原因であることが多い。
閉塞状態→準備完了状態:待ち条件が満たされており、プロセッサに割り当てられて実行可能。
実行中状態→準備完了状態: 自己の理由によるものではなく、外部的な理由により、実行中状態のプロセスがプロセッサを放棄し、準備完了状態になる。たとえば、タイム スライスが使い果たされた場合や、プロセッサを横取りする優先度の高いプロセスがある場合などです。
Ready 状態→Running 状態: システムは Ready キュー内のプロセスを選択して、ある戦略に従ってプロセッサを占有し、この時点で Running 状態になります。

オペレーティング システムのメモリの断片化を理解するにはどうすればよいですか?

メモリの断片化は通常、内部断片化と外部断片化に分けられます。

  1. 内部断片化は、固定サイズのメモリ パーティションの使用が原因で発生します。内部断片化は、プロセスに割り当てられた固定メモリ領域をプロセスが完全に使用できない場合に発生します。通常、内部の破片を完全に回避することは困難です
  2. 外部断片化とは、未割り当ての連続メモリ領域が小さすぎてプロセスのメモリ割り当て要求を満たすことができないため、プロセスが利用できないメモリ領域です。

解決策は何ですか

一般的に使用されるメモリ割り当て方法は、セグメント ページ メモリ割り当てです。メモリをセグメントに分割し、各セグメントを固定サイズのページに分割します。ページ テーブル メカニズムにより、セグメント内のページが同じメモリ領域に連続している必要はありません。

仮想メモリ

仮想メモリとは、リクエストを呼び出す機能を持ち、メモリ容量を論理的に拡張できるメモリシステムである.仮想メモリには、多重性、互換性、仮想性の3つの特徴がある.プログラムを複数回呼び出すことができる.メモリは、より大きなユーザープログラムを実行できる.より小さなユーザー空間で実行されるため、より多くのプロセスを同時に実行できるため、システムのスループットが向上します。ページ フォールトが発生すると、メモリの管理方法に応じて、セグメントまたはページのいずれかが読み込まれます。仮想性とは、仮想メモリと物理メモリのマッピングを意味します。

Linux では、プロセスはメモリの物理アドレスを直接読み書きすることはできず、[仮想メモリ アドレス] にしかアクセスできません。オペレーティング システムは、仮想メモリ アドレス -> 物理アドレスを配置します。

仮想メモリは、限られたメモリ スペースで大規模なアプリケーションをロードし、必要に応じてメモリとディスクの間でデータを移動するという問題を解決します。

セグメント ページ テーブルの形式により、仮想メモリ内の連続したメモリ空間がメイン メモリにマッピングされ、メイン メモリ空間内のプログラム セグメントが連続しない場合があります。

ページネーションとは?

メインメモリの基本単位として、メモリ空間を同じサイズのブロックに分割します。プログラムデータは異なるページに格納され、ページはメモリに離散的に分散されるため、ページ番号から物理ブロック番号へのマッピングを実現するためのマッピング関係を記録するページテーブルが必要です。

ページング システムでメモリ データにアクセスするには、2 つのメモリ アクセスが必要です (1 つは、メモリからページ テーブルにアクセスし、そこから指定された物理ブロック番号を見つけ、ページにオフセットを追加して実際の物理アドレスを取得することです。初回に基づいて実際の物理アドレスを取得する) 物理アドレス アクセス メモリにデータをフェッチする)。

セグメンテーションとは

ページングは​​メモリ使用率を改善するためのものであり、セグメンテーションはコードを記述する際のプログラマのロジック要件 (データ共有、データ保護、動的リンクなど) を満たすためのものです。

セグメント化されたメモリ管理では、アドレスは 2 次元、1 次元はセグメント番号、2 次元はセグメント内のアドレスであり、各セグメントの長さは異なり、各セグメントのアドレス指定は 0 から始まりますセグメント管理では、各セグメントには連続したメモリが割り当てられますが、セグメントは離散的に割り当てられるため、セグメント テーブルのメカニズムに対応して、論理アドレスと物理アドレスの間にもマッピング関係があります。

ページングとセグメンテーションの違いは何ですか?

  • ページングは​​プログラマーには透過的ですが、セグメンテーションではプログラマーが各セグメントを明示的に分割する必要があります。
  • ページングのアドレス空間は 1 次元のアドレス空間であり、セグメンテーションは 2 次元です。
  • ページ サイズは不変で、セグメント サイズは動的に変更できます。
  • ページングは​​主に仮想メモリを実装してより大きなアドレス空間を取得するために使用され、セグメンテーションは主にプログラムとデータを論理的に独立したアドレス空間に分割し、共有と保護を容易にするために使用されます。

ページ置換アルゴリズム

ページを置き換える理由:

アプリケーション プログラムは複数回メモリにロードされるため、一定時間実行すると必ずページ フォールトが発生します。アドレス マッピング プロセス中に、アクセスするページがメモリ内にない場合、ページ フォルト割り込みが生成されます。この時点で、オペレーティング システムはメモリ内のページを選択してメモリから移動し、ページを転送するためのスペースを確保する必要があります。どのページを削除するかを選択するルールは、ページ置換アルゴリズムです

いくつかのページ置換アルゴリズム:

最適な置換アルゴリズム (理想) : 現在のページで今後最も長くアクセスされないページを置換します。

先入れ先出し: 最も早くロードされたページを除外します

LRUは最も長い間使用されていません:各ページには、ページが現在までに最後にアクセスされた時間を記録するtがあり、最大のt値を持つページは、置き換えられるたびに置き換えられます(レジスタまたはスタックで実装されています)

クロック アルゴリズム クロック(最近使用されていないアルゴリズム NRU とも呼ばれます): ページはアクセスするように設定され、ページを循環リストにリンクします。各ページにはアクセス ビット 0/1 があり、1 はレスキューされる別の機会を意味し、次のサイクルポインタがそれを指している場合、この置換は免除できますが、アクセス位置は 0 に設定されます。これは、次にループ ポインタに遭遇した場合に置換する必要があることを意味します。ページがアクセスされると、アクセス ビットが 1 にセットされます。ページが置き換えられるとき、現在のポインターのアクセス ビットが 0 の場合は置き換え、それ以外の場合はこの値を 0 に設定し、アクセス ビットが 0 のページに遭遇するまでループします。

改善されたクロック アルゴリズム: クロック アルゴリズムに変更ビットを追加し、最初にアクセス ビットと変更ビットの両方が 0 でページを置き換え、次にアクセス ビットが 0 で変更ビットが 1 でページを置き換えます。

最も使用されていないアルゴリズム LFU : ページの訪問数を記録するようにレジスタを設定し、毎回現在の訪問数が最も少ないものを置き換えます。

ユーザーモードとカーネルモード

カーネル モード: CPU は、ハード ディスク、ネットワーク カードなどの周辺機器を含むメモリ内のすべてのデータにアクセスできます。また、CPU は、あるプログラムから別のプログラムに切り替えることもできます。

ユーザーモード: メモリへのアクセスが制限され、周辺機器へのアクセスがなく、CPU を占有する能力が奪われ、他のプログラムが CPU リソースを取得できます。

最大の違いは、パーミッションが異なることで、ユーザー モードで実行されているプログラムは、オペレーティング システムのカーネル データ構造やプログラムに直接アクセスできません。

なぜこの 2 つの状態があるのでしょうか。

カーネルは高速ですが、リソースが限られており、制御できるプロセスが多くないため、低速のユーザー モードの支援が必要ですが、ユーザー モードが悪用されるのを防ぐために、ユーザーの権限はモードプログラムは制限されています。

異なるプログラム間のアクセスを制限して、他のプログラムのメモリデータを取得したり、周辺機器のデータを取得してネットワークに送信したりできないようにする必要があります.CPUは、ユーザーモードとカーネルモードの2つの許可レベルに分けられます.

いつ変換するか

1. システムコール:

ユーザープロセスによって開始されます。ユーザーモードのプロセスは、オペレーティングシステムが提供するサービスプログラムを使用して、システムコールを通じて作業を完了するように要求します.たとえば、fork()は、システムコールを実行して新しいプロセスを作成することです.

ユーザー プログラムはシステム コールを使用し、システム コールはカーネル モードに変換され、オペレーティング システムを呼び出します。

2. 例外が発生します:

現在実行中のプロセスから、この例外を処理するカーネル関連のプログラムに切り替えます

3.周辺機器の中断:

すべてのプログラムはユーザーモードで実行されますが、ハードディスクからデータを読み取ったり、キーボードから入力したりする場合、これらのことを実行できるのはオペレーティング システムだけであり、プログラムはオペレーティング システムにこれらの操作をプログラムの名前で実行するように要求する必要があります。 . このとき、ユーザーモードプログラムはカーネルモードに切り替わります。

バッファオーバーフローとは何ですか? 害は何ですか?

バッファ オーバーフローとは、コンピュータがバッファ自体の容量を超えるデータでバッファを埋めると、オーバーフローしたデータが正当なデータに上書きされることを意味します。

次の 2 つの危険があります。

  • プログラムがクラッシュし、サービス拒否が発生する
  • 悪意のあるコードをジャンプして実行する

バッファ オーバーフローの主な原因は、ユーザー入力がプログラムで注意深くチェックされていないことです。

I/O 多重化

IO 多重化とは、カーネルが、プロセスによって指定された 1 つ以上の IO 条件を読み取る準備ができていることを検出すると、そのプロセスに通知することを意味します。IO 多重化は、次の場合に適用できます

  • クライアントが複数の記述子 (通常は対話型入力およびネットワーク ソケット) を処理する場合は、I/O 多重化を使用する必要があります。
  • クライアントが複数のソケットを同時に処理することは可能ですが、まれです。
  • TCP サーバーがリスニング ソケットと接続されたソケットの両方を処理する場合、通常は I/O 多重化が使用されます。
  • サーバーが TCP と UDP の両方を処理する必要がある場合は、通常、I/O 多重化が使用されます。
  • サーバーが複数のサービスまたは複数のプロトコルを処理する場合、通常は I/O 多重化が使用されます。
  • マルチプロセスおよびマルチスレッド技術と比較して、I/O 多重化技術の最大の利点は、システムのオーバーヘッドが小さいこと、システムがプロセス/スレッドを作成する必要がなく、これらのプロセス/スレッドを維持する必要がないことです。したがって、システムのオーバーヘッドが大幅に削減されます。

おすすめ

転載: blog.csdn.net/Tyson0314/article/details/130171476