メインコンテンツまでスキップ

OS

OSとは

コンピューターシステムにおいてハードウェアとアプリケーションの橋渡しを行う。

  • ハードウェアを抽象化してアプリケーションのインターフェースを提供する

たとえば、外部記憶装置にファイルを書き込む場合、その外部記憶装置はSATA接続のハードディスクかもしれませんし、NVMe接続のSSDかもしれませんし、はたまたUSBメモリかもしれません。しかも、各ディスクのファイルシステムは全部違うかもしれません。そんな状況でもアプリケーションは書き込み先のファイルをfopenしてwriteするだけで、書き込み先のデバイスが一体何なのかを気にせず書き込むことができます。これが「ハードウエアを抽象化して、アプリケーションにインターフェイスを提供する」ということなのです

  • 計算資源を複数のアプリケーションに分配する

また、CPUは一般的に1コアで1つのアプリケーションしか動作させることができません。それでも、私たちはCPUのコア数より多くのアプリケーションを起動し、まるで同時に動いているかのように感じることができます。これは、OSがCPUの時間を細かい単位に分割し、各アプリケーションを切り替えつつ実行するよう調整しているからなのです。これが「計算資源を複数のアプリケーションに分配する」という機能の例です。

OSの基本構造

カーネルはコンピューターの基本的な操作を行う機能を格納したライブラリ群のようなもので、コマンドやライブラリはこのカーネルの中にあるライブラリ(システムコール)を呼び出す。 例としてlsコマンドはC言語で書かれているが、その中でgetdentsというシステムコールを呼びファイルのリストを取得している。 つまりプロセスはOS内のコマンドやライブラリを呼び出し、そのコマンドやライブラリはカーネル内のシステムコールを呼び出している。 ここからはオペレーティングシステムのコンセプトを理解する。 以下のように追記すると、OSの基本構造についての詳細な情報が得られます。

  • コマンドやライブラリ:

    • ユーザ空間: アプリケーションやユーザープログラムが動作する領域。
      • シェル: ユーザーがコマンドを入力して実行するインターフェース。
      • システムコールインターフェース: ユーザープログラムがカーネル機能を呼び出すためのAPI。
      • ライブラリ: 共通機能を提供するコードの集まり。プログラムが効率よく開発・実行できるように支援する。
      • アプリケーションプログラム: ユーザーが利用するためのソフトウェア(例: ブラウザ、エディターなど)。
  • カーネル:

    • プロセスマネージャー: プロセスの作成、スケジューリング、終了を管理する。
      • プロセス: プログラムの実行単位で、独立したアドレス空間を持つ。
      • スレッド: プロセス内の実行単位で、プロセス内のリソースを共有する。
    • メモリマネージャー: プロセスが使用するメモリの割り当てと解放を管理する。
    • ファイルシステム: ディスク上のファイルの読み書き、作成、削除を管理する。
    • デバイスドライバー: ハードウェアデバイスとの通信を管理する。
    • システムコールインターフェース: ユーザープログラムからカーネル機能への呼び出しを提供するAPI。
    • セキュリティマネージャー: アクセス権限の管理やユーザー認証を行う。
  • デーモンやサービス:

    • デーモン: バックグラウンドで動作するプロセスで、システムのサービスやメンテナンスを行う。
    • サービス: 特定の機能を提供するプログラムで、ネットワークサービス(例: Webサーバ、データベースサーバ)などが含まれる。
  • ネットワークスタック:

    • プロトコルスタック: ネットワーク通信を行うためのプロトコルを実装する。
    • ネットワークドライバー: ネットワークインターフェースカード(NIC)との通信を管理する。
  • ユーザーインターフェース:

    • グラフィカルユーザーインターフェース(GUI): ユーザーが視覚的に操作するためのインターフェース。
    • コマンドラインインターフェース(CLI): ユーザーがテキストベースでコマンドを入力するためのインターフェース。

このように、OSは多くの構成要素で成り立っており、それぞれが連携してシステム全体の機能を提供します。


OSとCPUの関係

OSとCPUの関係を理解するには、OSがどのようにCPUを管理し、プロセスやスレッドを実行するかを知ることが重要です。以下に、その関係を説明します:

  1. CPUスケジューリング:

    • プロセススケジューリング: OSはCPUの時間を複数のプロセス間で公平に分配する必要があります。これをCPUスケジューリングと呼びます。スケジューリングアルゴリズムには、ラウンドロビン、優先度スケジューリング、最短ジョブ優先などがあります。
    • スレッドスケジューリング: マルチスレッドアプリケーションの場合、OSは各スレッドに対してもCPU時間を割り当てます。スレッドは同じプロセス内でメモリやリソースを共有するため、スレッドスケジューリングは効率的なリソース利用を実現します。
  2. コンテキストスイッチ:

    • プロセスやスレッドの実行が切り替わるとき、OSは現在のプロセスやスレッドの状態を保存し、新しいプロセスやスレッドの状態をロードします。これをコンテキストスイッチと呼びます。コンテキストスイッチはオーバーヘッドがあるため、効率的に行う必要があります。
  3. 割り込み処理:

    • ハードウェア割り込み: 外部デバイス(キーボード、マウス、ディスクドライブなど)がCPUに割り込みを発生させ、OSに処理を要求します。OSは現在のタスクを一時停止し、割り込み処理を行います。
    • ソフトウェア割り込み: プログラムが特定の条件を満たしたときに割り込みを発生させます。これにより、OSは適切な処理を行うことができます。
  4. マルチコアプロセッシング:

    • マルチコアCPU: 近代的なCPUは複数のコアを持ち、各コアが独立して命令を実行できます。OSはこれらのコアを利用して、並行処理を行い、システム全体のパフォーマンスを向上させます。
    • スレッドとプロセスの並列実行: マルチコアCPUを利用することで、複数のスレッドやプロセスが同時に実行されます。OSはスケジューラを使って、どのスレッドやプロセスをどのコアで実行するかを管理します。

CPUの役割

  1. 命令実行:

    • フェッチ: CPUはメモリから命令を読み取ります。
    • デコード: 読み取った命令を解釈します。
    • 実行: 命令に基づいて計算を行います。
    • 書き戻し: 結果をレジスタやメモリに書き込みます。
  2. 演算処理:

    • CPUは算術演算(加算、減算、乗算、除算など)や論理演算(AND、OR、NOTなど)を高速に行います。
  3. レジスタ管理:

    • レジスタはCPU内部の高速なメモリで、データや命令の一時的な保存に使用されます。
  4. キャッシュ管理:

    • L1/L2/L3キャッシュ: キャッシュはメモリへのアクセス時間を短縮するための高速メモリです。CPUはキャッシュを利用して、頻繁にアクセスするデータを高速に取得します。

まとめ

  • OSの役割: プロセスとスレッドの管理、メモリ管理、ファイルシステム管理、デバイス管理、ネットワーク管理、セキュリティ管理など。
  • CPUの役割: 命令の実行、演算処理、レジスタとキャッシュの管理、割り込み処理など。

OSはCPUのリソースを効率的に管理し、複数のタスクを並行して実行するための機能を提供します。CPUはOSの指示にしたがって命令を実行し、システム全体のパフォーマンスを維持します。この相互作用により、ユーザーは効率的でスムーズなコンピューティング体験を享受できます。


プロセス管理(プロセスマネージャー)

  • プロセス プログラムの実行単位であり、CPU時間単位で割り振られる。状態(ステート)があり、現在処理中であるRunning状態だったり、実行可能状態であるReadyなどが存在。 CPUがプロセスを実行する場合、そのプロセスが持つメモリデータに対して演算を行う。 プロセスはテキストセグメントとデータセグメントからなる構造データをメモリ上に持っている。 テキストセグメント プログラムの命令列 データセグメント PDA (Processor Data Area)と呼ばれる、プロセッサの情報やプロセス管理用のデータ領域 データ領域と呼ばれる、定数等が置かれる静的領域と、通常の変数等が置かれるヒープ領域からなる領域 スタック領域と呼ばれる一時的なデータ保管領域

ファイルディスクリプター(fdともいう)

参考URL

ソケットを扱う上で切り離せないのがファイルディスクリプター
fdとはファイルやソケットなどを抽象化した仕組み。
ファイルディスクリプターという名称だが、ファイルに限らず標準入出力、ソケット、ブロックデバイス、ディスプレイなど何でも「ファイルを扱うように」扱える

オブジェクト指向のポリモーフィズムの考え方に近い Go言語でいうとio.Readerやio.Writerに近いです。抽象化された入出力によって汎用的な使い方ができます。

fd番号

fdは単なる整数で、その数字で識別されます。fdはプロセス毎に管理されますが、そのうち0~2はあらかじめ決まっていて

0: 標準入力 1: 標準出力 2: 標準エラー出力 となってます。それ以降は新しくfdが必要となった時に小さい番号順で作られ、クローズされると同じ番号が再利用されます。

fd保存場所

fdはプロセス毎に管理されるため、/proc/プロセス番号/fd/に保持されています。 また

$ lsof -p プロセス番号 で番号を確認できます。

ソケット

ソケットとポート番号のそれぞれの役割を知る Webサーバにおけるソケット周りの知識

ソケットを理解するとわかること

  • TCPセッションの流れ
  • ulimitでnofileを上げないとコネクション増加した時のToo many open filesが出るのはなぜか
  • なぜサーバの待ち受けポートは1つで、クライアントのポートは接続するたびに新しいポートが必要なのか
  • unix domain socketはなぜファイルパスを指定するのか

ソケットはネットワーク通信に用いる際のファイルディスクリプターです。 これはTCP/UDPのような外部ネットワークに繋がるインターフェースとしても使われますし、Unixドメインソケットのようなカーネル内部で完結するネットワークインターフェースとしても使われます。

コンピューターーがTCP/IPを使って通信をするとき、IPプロトコルやTCPプロトコルの機能は大抵、OSの機能として実現される。 一般にWebブラウザやメーラーといったアプリケーションプログラムはAPIと呼ばれる仕組みでOSの機能を呼び出している。 ソケット(socket)はTCP/IPの機能を利用する時に使う標準的なAPIでポート番号はそこで使われる識別子

  • ソケットの経緯

BSD UNIXはTCP/IPを使ったネットワーク機能を搭載していたうえに、プログラムのソースコードを無料で公開したので、BSD UNIXとソケットAPIはTCP/IPを使う通信ソフトを開発する際のリファレンス(基本となる手法)になりました。TCP/IPの普及に伴い、ソケットは通信ソフトがOSのTCP/IP機能を利用するAPIとしてデファクト・スタンダードの地位を確立しました。

ソケットはプロセスの持つ出入り口。プロセス間で通信を行う場合やプロセスからインターネットに繋ぐ場合の口となる。

ソケット通信 HTTP通信違い

かなり深く追求している

HTTPはクライアントがリクエストすることによってサーバがレスポンスする。 クライアントが発信することから始まるため逆にサーバーがリクエストすることはない。 ソケット通信の場合はサーバとクライアントが特定のポートを通じて双方向にリアルタイムで通信することが可能。

  1. POSIXの基礎
  2. ネットワーキングコンセプト

標準入力/標準出力/

あらゆるプロセスには、stdin、stdout、stderrという3つの標準ストリームがあることをしる

別の記事だけど参考になる(Node.jsでログを記録する方法)

標準入力 [standard input] stdin

コンピューターの入力装置やOSが提供するデータ入力機能・経路などを指し、多くのシステムではキーボード装置による利用者の文字入力が標準入力に設定されている。 システム上では “stdin” の略号で表されることが多い。

標準出力 [standard output] stdout

コンピューターの出力装置やOSが提供するデータ出力機能・経路などを指し、多くのシステムではディスプレイ装置による利用者への文字表示が標準出力に設定されている。 システム上では “stdout” の略号で表されることが多い。

topic JSのconsole.logはこれにあたる

標準エラー出力

UNIXの命令やGMTの命令の多くはエラーメッセージを出力することがある。 これは標準出力(stdout)とは違う書き出し先に書き込まれる。これを標準エラー出力(stderr)という。

topic JSのconsole.errorはこれにあたる


改行コード

参考URL

対応OSと改行コードが違うということは、プログラムを読み込めなくなることを意味する

種類

種類

改行コードには以下のものがある。

CR(Carriage Return キャリッジ・リターン) 説明:「キャリッジ・リターン」とは、タイプライター時代にキャリッジ(印刷ヘッド)が紙の左端に戻る動作を指します。コンピューターではこれが「カーソルを行の左端に戻す」動作に相当します。 コード: \r 対応OS: 昔のMac OS(Mac OS 9以前)

LF(Line Feed ラインフィード) 説明:「ラインフィード」とは、タイプライターで紙を一行分上に送る動作を指します。コンピューターではこれが「カーソルを次の行に移動する」動作に相当します。 コード: \n 対応OS: Linux、UNIX、macOS(macOSX以降)

CR + LF (Carriage Return キャリッジ・リターン + Line Feed ラインフィード) 説明: CRとLFの組み合わせで、カーソルを行の左端に戻し、その後に次の行に移動します。これはタイプライターの動作を再現したもので、行末から新しい行の先頭にカーソルを移動させます。 コード: \r\n 対応OS: Windows

なぜCRやLFが使われるのか? 歴史的背景: タイプライターから始まったCRとLFの概念は、コンピューターにも引き継がれました。タイプライターでは、印字位置を左端に戻し、用紙を一行分送るために別々の操作が必要でした。これがコンピューターの改行処理にも反映されました。

OSの違い: 異なるOSはそれぞれの歴史的背景や設計方針に基づいて改行コードを選択しました。古いMac OSはCRを使い、UNIX系システムはLFを採用し、Windowsは両方の組み合わせを使用しています。

UID

UIDとはUNIX系のOSで使用される、利用者識別用の番号のこと。

デーモンやエージェントを含めて説明すると、プロセスやスレッドの概念がより広がります。以下に、それぞれの違いと特徴を含めて説明します。

プロセス

  • 定義: 実行中のプログラムのインスタンス。
  • 特徴:
    • 独立性: 独自のメモリ空間を持つ。他のプロセスとメモリを共有しない。
    • リソース: 独自のリソース(ファイルディスクリプター、メモリ領域など)を持つ。
    • コンテキストスイッチ: プロセス間の切り替えはコストが高い。

スレッド

  • 定義: プロセス内で実行される実行単位。
  • 特徴:
    • 共有: 同じプロセス内でメモリやリソースを共有する。
    • 軽量性: スレッドの切り替えは低コスト。
    • 並行性: 複数のスレッドが並行して実行されることで、並列処理が可能。

デーモン

  • 定義: バックグラウンドで実行されるプロセス。
  • 特徴:
    • 常駐性: システムの起動時に開始し、シャットダウンまで常駐する。
    • 用途: サーバープロセス(例: Webサーバー、データベースサーバー)。
    • 操作: 通常はユーザーの直接操作を受けず、システムや他のプログラムから指示を受ける。

エージェント

  • 定義: 特定のタスクやサービスを実行するために設計されたプロセスやスレッド。
  • 特徴:
    • 機能特化: 特定のタスクやサービスに特化している。
    • 通信: 他のエージェントやシステムと通信して協調動作を行う。
    • 動的性: 一般的に、ユーザーやシステムの要求に応じて動的に動作する。

比較と実用例

  • プロセス: 各タブが独立したプロセスとして動作するWebブラウザ。
  • スレッド: Webサーバーがリクエストごとにスレッドを作成して処理。
  • デーモン: システム起動時に自動的に開始するHTTPサーバー(例: Apache、Nginx)。
  • エージェント: システム監視ツールのエージェント(例: Datadogエージェント、New Relicエージェント)。

プロセスとスレッドの違い

  • メモリの分離:
    • プロセス: 独立したメモリ空間を持つ。
    • スレッド: 同じプロセス内でメモリを共有する。
  • リソースの共有:
    • プロセス: 独立したリソースを持つ。
    • スレッド: プロセス内でリソースを共有する。
  • コンテキストスイッチ:
    • プロセス: 高コスト。
    • スレッド: 低コスト。

デーモンとエージェントの役割

  • デーモン: 長期間実行されるサービスやバックグラウンドタスクを提供。
  • エージェント: 特定のタスクやサービスを実行し、必要に応じて他のシステムやエージェントと協力。

これらの概念を理解することで、システム設計やパフォーマンス最適化に役立ちます。

+-------------------------------------------------+
| Process |
| +-------------------------------------------+ |
| | Memory Space | |
| | +------------------+ +------------------+ |
| | | Thread 1 | | Thread 2 | |
| | +------------------+ +------------------+ |
| | | Thread 3 | |
| | +------------------+ |
| +-------------------------------------------+ |
+-------------------------------------------------+

+-----------------------------------------------+
| Daemon |
| +------------------+ +------------------+ |
| | Agent 1 | | Agent 2 | |
| +------------------+ +------------------+ |
+-----------------------------------------------+

説明

  1. Process: プロセスは独立した実行環境を持ち、それぞれのプロセスは独自のメモリ空間を持っています。

    • Memory Space: プロセス内で使用されるメモリ空間。
    • Threads: スレッドは同じプロセス内のメモリ空間を共有して実行される軽量な単位です。例えば、Thread 1, Thread 2, Thread 3 があります。
  2. Daemon: デーモンはバックグラウンドで実行されるプロセスであり、通常はシステムレベルのサービスを提供します。

    • Agents: エージェントはデーモンによって実行される特定のタスクを担当するサブプロセスです。例えば、Agent 1Agent 2 があります。

このようにプロセスはスレッドを含み、デーモンはエージェントを含むことができます。プロセスは独自のメモリ空間を持ち、スレッドはそのメモリ空間を共有します。デーモンとエージェントは、特定のバックグラウンドタスクを処理するために使用されます。