「オペレーティングシステムの概要」に関する調査ノート(1):オペレーティングシステムの概要


このシリーズの記事は、主にウィスコンシン大学の「オペレーティングシステム:3つの簡単な小品」とそのサポートコースCS-537(オペレーティングシステム入門)の学習ノートです。同時に、この期間中にいくつかのわかりやすい資料が点在します。

概観

オペレーティングシステムの導入は、仮想性、同時実行性、永続性などの3つの設計オペレーティングシステムの本質から始まり、従来のオペレーティングシステムのプロセス管理、メモリ管理、ファイル管理、およびI / O管理を通じて実行されます。

仮想性 並行性 持続性
プロセス管理 プロセス、CPUスケジューリング スレッド、デッドロック、プロセス同期
メモリ管理 メモリ管理
ストレージ管理 I/O系统 ファイルシステム、大容量ストレージ

なぜオペレーティングシステムが必要なのですか?

ここに画像の説明を挿入
コンピュータシステムは、下から上に向かって、コンピュータハードウェア、オペレーティングシステム、システム、およびアプリケーションソフトウェアに大別できます。ユーザーはソフトウェアレイヤーで作業し、Word、Matlab、その他のソフトウェアを使用して独自の目的を達成します。ハードウェアの観点から見ると、コンピューターはCPUのフェッチ、デコード、実行のプロセスにすぎません。したがって、アプリケーションソフトウェアをハードウェアに合理的に接続するには、2つの間のインターフェイスとしてオペレーティングシステムソフトウェアを導入する必要があります。
ここに画像の説明を挿入
オペレーティングシステムソフトウェアの本質は無限循環プログラムであり、起動後、プログラムが強制的にシャットダウンされるまで、ユーザーの指示を受け入れ続けます。ベースのMacOS、Linuxや他のシステム、およびダウンロードcommon.hなどのヘッダは、私たちは、オペレーティングシステムを実行するプロセスをシミュレートすることができます。

// cpu.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>
#include "common.h"

int main(int argc, char *argv[])  // argc 命令行参数个数
{								  // argv 命令行参数向量
  if (argc != 2) {
    fprintf(stderr, "usage: cpu <string>\n");
    exit(1);
  }

  char *str = argv[1];
  while (1) {
    Spin(1);
    printf("%s\n", str);
  }

  return 0;
}

スピン()関数:common.hにあり、プログラムの出力間隔を
gcc -o実行しますファイル名ソースファイル名:ソースファイルをコンパイルします
Wall:コンパイル後にすべての警告を表示します
Werror:すべての警告をエラーとして処理し
ここに画像の説明を挿入
、コマンドhello 実行しますプログラムが強制的に終了するまで、プログラムはhelloを出力し続けることがわかります。
ここに画像の説明を挿入
さらにいくつかのコマンドを入力すると、プログラムは3つのコマンドを同時に出力するため、ユーザーは複数のCPUが同時にコマンドを実行しているように錯覚しますこれはCPUの仮想化です。

仮想化

仮想化とは、物理エンティティをいくつかの論理的な対応物にマッピングすることであり、実装方法は、時分割多重化と空間分割多重化です。メモリ仮想化をシミュレートし、getpid()を介してプロセス番号を取得し、ポインターpでデータを更新して、データストレージアドレスを取得できます。

// mem.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.h"

int main(int argc, char *argv[])
{
  if (argc != 2) {
    fprintf(stderr, "usage: mem <value>\n");
    exit(1);
  }
  
  int *p = malloc(sizeof(int));
  assert(p != NULL);                         // getpid() 进程识别码   p 指向内存的指针
  printf("(pid:%d) addr of p:        %llx\n", (int)getpid(), (unsigned long long)p);
  printf("(pid:%d) addr stored in p: %llx\n", (int)getpid(), (unsigned long long)p);
  
  *p = atoi(argv[1]); // assign value to addr stored in p
  while (1) {
    Spin(1);
    *p = *p + 1;
    printf("(pid:%d) p: %d\n", getpid(), *p);
  }
 
  return 0;
}

ここに画像の説明を挿入
ここに画像の説明を挿入
この時点で、私のマシンで2つのプロセスが実行されています。プロセス番号は11984と11985、ストレージアドレスは7fbf56c01720と7fb86cc01720で、それぞれ1000と2000から1ずつ増加します。

同意

同時実行とは、マクロで同じ時間間隔内に複数のプロセスを実行することで、オペレーティングシステムはプロセスとスレッドを実装します。

// threads.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "common.h"

volatile int counter = 0;  // 本条指令不会因编译器的优化而省略,且要求每次直接读值。
int loops;

void *worker(void *arg) {  // 计数器
  int i;
  for (i = 0; i < loops; i++) {
    counter++;
  }
  return NULL;
}

int main(int argc, char *argv[]) {
  if (argc != 2) {
    fprintf(stderr, "usage: threads <value>\n");
    exit(1);
  }

  loops = atoi(argv[1]);
  pthread_t p1, p2;		// 声明线程id
  printf("Initial value : %d\n", counter);

  pthread_create(&p1, NULL, worker, NULL);
  pthread_create(&p2, NULL, worker, NULL);
  pthread_join(p1, NULL);
  pthread_join(p2, NULL);
  printf("Final value   : %d\n", counter);
  return 0;
}

pthread_create():スレッドを作成し、関連するスレッド関数を実行します。
最初のパラメーターは、スレッドIDへのポインターです。
2番目のパラメーターは、スレッド属性を設定するために使用されます。
3番目のパラメーターは、スレッド実行関数の開始アドレスです。
最後のパラメーターは、実行中の関数のパラメーターです。

pthread_join():現在のスレッドのブロック/スレッドリソースの再利用
。最初のパラメーターはスレッド識別子です
。2番目のパラメーターは、待機中のスレッドの戻り値を格納するために使用されるユーザー定義のポインターです。
ここに画像の説明を挿入
プログラムは2つのスレッド実行カウンターworker()関数を作成します。初期値は0、パラメーターループは1000、結果は2000です。ただし、パラメータが大きい場合、結果は期待値より小さくなる場合があります。これは、2つのカウンタースレッドが同じカウンターを共有し、2つのスレッドがカウンターを取得して同時に実行する可能性があるためです。解決策は、カウンター、つまりPV操作をロックすることです。

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;    // 全局信号量初始化
void *worker(void *arg) {
  int i;
  for (i = 0; i < loops; i++) {
    pthread_mutex_lock(&m);		// 上锁
    counter++;
    pthread_mutex_unlock(&m);	// 开锁
  }
  printf("%d\n", counter);
  pthread_exit(NULL);
}

ここに画像の説明を挿入

持続性

永続性とは、一時的なデータ(メモリ内のオブジェクトなど)を、永続的に保存できるストレージデバイス(ディスクなど)に保存することです。

// io.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>

void dowork()
{
  int fd = open("/tmp/file", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
  assert(fd >= 0);
  
  char buffer[20];
  sprintf(buffer, "hello world\n");
  int rc = write(fd, buffer, strlen(buffer));
  assert(rc == (strlen(buffer)));
  printf("wrote %d bytes\n", rc);
  
  fsync(fd);
  close(fd);
}
int main(int argc, char *argv[]) {
  dowork();
  return 0;
}

catコマンド:ファイルの内容を表示する
ここに画像の説明を挿入

重要なコンセプト

オペレーティングシステム:コンピューターシステム全体のハードウェアおよびソフトウェアリソースを制御および管理し、コンピューターワークフローを合理的に制御し、ユーザーおよびその他のソフトウェアに便利なインターフェイスと環境を提供します。

同時実行性:一定の期間、マクロ上で同時に複数のプログラムが実行されますが、シングルプロセッサシステムでは、一度に1つのプログラムしか実行できないため、これらのプログラムは微視的に交互にしか実行できません。
並列処理:2つ以上のイベントが同時に発生します。マクロレベルでは、CPUとI / Oデバイスは並列です。マイクロレベルでは、CPUは同時に複数の命令を実行します。マルチステージパイプラインまたはマルチコアプロセッサを導入して実装する必要があります。

相互に排他的な共有:重要なリソースに同時にアクセスできるのは1つのプロセスだけであり、同期メカニズムが導入されています。
時分割多重化:各プロセスは一定量のCPU時間を順番に使用し、時間が経過するとすぐに次のプロセスに切り替えます。
スペース分割多重化:メモリは固定サイズのページフレームに分割され、各プロセスも固定サイズのページに分割されます。これらは部分的にメモリにマップされ、ページが欠落している場合はページ置換アルゴリズムを使用してページを置き換えます。

非同期性:プロセスは一度に完了せず、停止して予測できない速度で前進します。

「オペレーティングシステムの概要」調査ノート(2):CPU仮想化(プロセス)

元の記事21件を公開 賞賛された8件 訪問1495件

おすすめ

転載: blog.csdn.net/K_Xin/article/details/104543586