<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
	<id>https://uc2.h2np.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hironobu</id>
	<title>UnixClassWiki - 利用者の投稿記録 [ja]</title>
	<link rel="self" type="application/atom+xml" href="https://uc2.h2np.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hironobu"/>
	<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E7%89%B9%E5%88%A5:%E6%8A%95%E7%A8%BF%E8%A8%98%E9%8C%B2/Hironobu"/>
	<updated>2026-04-30T21:39:20Z</updated>
	<subtitle>利用者の投稿記録</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1774</id>
		<title>スワップの運用について考えてみる</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1774"/>
		<updated>2025-12-10T09:21:18Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* システムにおけるスワップ運用の私見 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== システムにおけるスワップ運用の私見 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのスワップ　～正確にはページフォルトですが～ は、どう運用すべきかを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずスワップが必要か、必要でないかといえばスワップ領域は必要です。&lt;br /&gt;
実メモリ（物理的なメモリ）は、プログラムのメモリ空間だけではなく、I/Oのキャッシュバッファとしても使われます。&lt;br /&gt;
プログラムが使わなくなったメモリ空間を抱えていて、一方でパフォーマンスのために必要なI/Oのキャッシュバッファが十分に確保できないのでは本末転倒です。使わなくなったメモリ空間をスワップに追い出すことができれば実メモリを有効に活用できることになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
古くから「メモリサイズの2倍か3倍のサイズを取る」というのが慣習的に行われています。&lt;br /&gt;
しかし、この数字はベストプラクティスであって、理論的背景があって決められている数字ではありません。&lt;br /&gt;
また大量の物理的メモリーを搭載する現在において2倍や3倍となるとかなりのスワップ領域を必要とすることになります。&lt;br /&gt;
一律の値ではなく、稼働させるアプリケーションと搭載メモリ量、そしてハードディスク搭載容量に依存するのはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux  [https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/8/html/managing_storage_devices/recommended-system-swap-space_getting-started-with-swap 13.2. システムの推奨スワップ領域]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの例からわかるのは4GBぐらいのメモリ量の場合は、同等なサイズ程度のスワップ領域で運用でき、十分なメモリ量がある場合、推奨される最小スワップ領域はメモリサイズよりかなり少なくなっています（ハイバネートの場合を除く）。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまり搭載しているメモリやハードディスクだけに着目して、スワップ領域のサイズを決定するのは、何か決定的な根拠があるわけではなく、ただこれくらいあれば良いだろうという目安程度の話になっていると考えられます。&lt;br /&gt;
あくまでも利用するマシンでどのようなアプリケーションがどのような形で動作し、また、どこまで耐えるのか、ということが判断のポイントであり、汎用な最適スワップ領域サイズの解はないといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
== 自分はどうしているか ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では私自身はどうしているかというと、搭載されているメモリ量ではなく、ハードディスクのパーティションを切る際に余った領域をスワップ領域に割り当てる方法を取っています。特定のスワップ領域のサイズをターゲットにして取っているわけではありません。&lt;br /&gt;
必要なパーティションを切っていって、最後余った領域をスワップパーティションとして残しています。1つのハードディスクでせいぜい数GB程度であり、現在数百GBから1TBを越えるハードディスクが利用される現在では、数GBはハードディスク領域としては無視出来るサイズです。尚、複数のハードディスクにスワップ領域を分散させるのは、高速化を狙っているためです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Proc-swap-san.png|thumb|center|640px|自分のサーバのスワップ領域の状況]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : 近年ではSSDのような高速な外部記憶装置があるので、そもそもスワップ領域を分散させる必要性は小さいかも知れませんし、また分散させるとなるとハードディスク時代には手に入らなかったような高速なスワップ領域になるでしょう。&lt;br /&gt;
&lt;br /&gt;
== まとめ ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
簡単にまとめると以下のようになります。&lt;br /&gt;
&lt;br /&gt;
* スワップの領域を確保することは必要です。&lt;br /&gt;
* アプリケーションや利用状況に関係なく汎用的に適切なスワップ領域サイズというものはありません。&lt;br /&gt;
* スワップ領域を決める時は慣用的なサイズで設定する場合が多いが、その根拠はきわめて曖昧です。&lt;br /&gt;
* 古典的なメモリ量の2倍のスワップ領域というのは、現在の大容量メモリ搭載時代では、あまり合理的な方法とはいえません。&lt;br /&gt;
* 複数のハードディスク上のパーティションを同時に利用する場合、個々のパーティションサイズは小さくとも総量としては大きい領域が確保できます。&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1773</id>
		<title>スワップの運用について考えてみる</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1773"/>
		<updated>2025-12-10T09:21:00Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* システムにおけるスワップ運用の私見 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== システムにおけるスワップ運用の私見 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのスワップ　～正確にはページフォルトですが～ は、どう運用すべきかを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずスワップが必要か、必要でないかといえばスワップ領域は必要です。&lt;br /&gt;
実メモリ（物理的なメモリ）は、プログラムのメモリ空間だけではなく、I/Oのキャッシュバッファとしても使われます。&lt;br /&gt;
プログラムが使わなくなったメモリ空間を抱えていて、一方でパフォーマンスのために必要なI/Oのキャッシュバッファが十分に確保できないのでは本末転倒です。使わなくなったメモリ空間をスワップに追い出すことができれば実メモリを有効に活用できることになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
古くから「メモリサイズの2倍か3倍のサイズを取る」というのが慣習的に行われています。&lt;br /&gt;
しかし、この数字はベストプラクティスであって、理論的背景があって決められている数字ではありません。&lt;br /&gt;
また大量の物理的メモリーを搭載する現在において2倍や3倍となるとかなりのスワップ領域を必要とすることになります。&lt;br /&gt;
一律の値ではなく、稼働させるアプリケーションと搭載メモリ量、そしてハードディスク搭載容量に依存するのはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux  [https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/8/html/managing_storage_devices/recommended-system-swap-space_getting-started-with-swap 13.2. システムの推奨スワップ領域]&lt;br /&gt;
&lt;br /&gt;
これらの例からわかるのは4GBぐらいのメモリ量の場合は、同等なサイズ程度のスワップ領域で運用でき、十分なメモリ量がある場合、推奨される最小スワップ領域はメモリサイズよりかなり少なくなっています（ハイバネートの場合を除く）。&lt;br /&gt;
&lt;br /&gt;
つまり搭載しているメモリやハードディスクだけに着目して、スワップ領域のサイズを決定するのは、何か決定的な根拠があるわけではなく、ただこれくらいあれば良いだろうという目安程度の話になっていると考えられます。&lt;br /&gt;
あくまでも利用するマシンでどのようなアプリケーションがどのような形で動作し、また、どこまで耐えるのか、ということが判断のポイントであり、汎用な最適スワップ領域サイズの解はないといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
== 自分はどうしているか ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では私自身はどうしているかというと、搭載されているメモリ量ではなく、ハードディスクのパーティションを切る際に余った領域をスワップ領域に割り当てる方法を取っています。特定のスワップ領域のサイズをターゲットにして取っているわけではありません。&lt;br /&gt;
必要なパーティションを切っていって、最後余った領域をスワップパーティションとして残しています。1つのハードディスクでせいぜい数GB程度であり、現在数百GBから1TBを越えるハードディスクが利用される現在では、数GBはハードディスク領域としては無視出来るサイズです。尚、複数のハードディスクにスワップ領域を分散させるのは、高速化を狙っているためです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Proc-swap-san.png|thumb|center|640px|自分のサーバのスワップ領域の状況]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : 近年ではSSDのような高速な外部記憶装置があるので、そもそもスワップ領域を分散させる必要性は小さいかも知れませんし、また分散させるとなるとハードディスク時代には手に入らなかったような高速なスワップ領域になるでしょう。&lt;br /&gt;
&lt;br /&gt;
== まとめ ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
簡単にまとめると以下のようになります。&lt;br /&gt;
&lt;br /&gt;
* スワップの領域を確保することは必要です。&lt;br /&gt;
* アプリケーションや利用状況に関係なく汎用的に適切なスワップ領域サイズというものはありません。&lt;br /&gt;
* スワップ領域を決める時は慣用的なサイズで設定する場合が多いが、その根拠はきわめて曖昧です。&lt;br /&gt;
* 古典的なメモリ量の2倍のスワップ領域というのは、現在の大容量メモリ搭載時代では、あまり合理的な方法とはいえません。&lt;br /&gt;
* 複数のハードディスク上のパーティションを同時に利用する場合、個々のパーティションサイズは小さくとも総量としては大きい領域が確保できます。&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1772</id>
		<title>スワップの運用について考えてみる</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1772"/>
		<updated>2025-12-10T09:12:09Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* システムにおけるスワップ運用の私見 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== システムにおけるスワップ運用の私見 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのスワップ　～正確にはページフォルトですが～ は、どう運用すべきかを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずスワップが必要か、必要でないかといえばスワップ領域は必要です。&lt;br /&gt;
実メモリ（物理的なメモリ）は、プログラムのメモリ空間だけではなく、I/Oのキャッシュバッファとしても使われます。&lt;br /&gt;
プログラムが使わなくなったメモリ空間を抱えていて、一方でパフォーマンスのために必要なI/Oのキャッシュバッファが十分に確保できないのでは本末転倒です。使わなくなったメモリ空間をスワップに追い出すことができれば実メモリを有効に活用できることになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
古くから「メモリサイズの2倍か3倍のサイズを取る」というのが慣習的に行われています。&lt;br /&gt;
しかし、この数字はベストプラクティスであって、理論的背景があって決められている数字ではありません。&lt;br /&gt;
一律の値ではなく、稼働させるアプリケーションと搭載メモリ量、そしてハードディスク搭載容量に依存するのはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux  [https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/8/html/managing_storage_devices/recommended-system-swap-space_getting-started-with-swap 13.2. システムの推奨スワップ領域]&lt;br /&gt;
&lt;br /&gt;
* Solaris のシステム管理 (デバイスとファイルシステム) [http://docs.oracle.com/cd/E19253-01/819-0386/fsswap-31050/index.html スワップ空間の計画]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの例からわかるのは「4GBぐらいのメモリ量の場合は、同等なスワップ領域であるが十分なメモリ量がある場合、スワップ領域はメモリサイズよりもはるかに少ない。」&lt;br /&gt;
「もし256GBのメモリ量で3倍のサイズとなると750GBとなり、現状、大容量ハードディスクが安くなったからといっても大きな領域を必要となり、システムを圧迫する。」ということです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまり搭載しているメモリやハードディスクだけに着目して、スワップ領域のサイズを決定するのは、何か決定的な根拠があるわけではなく、ただこれくらいあれば良いだろうという目安程度の話になっていると考えられます。&lt;br /&gt;
あくまでも利用するマシンでどのようなアプリケーションがどのような形で動作し、また、どこまで耐えるのか、ということがポイントであり、汎用な最適なスワップ領域サイズの解はないともいえます。&lt;br /&gt;
&lt;br /&gt;
== 自分はどうしているか ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では私自身はどうしているかというと、搭載されているメモリ量ではなく、ハードディスクのパーティションを切る際に余った領域をスワップ領域に割り当てる方法を取っています。特定のスワップ領域のサイズをターゲットにして取っているわけではありません。&lt;br /&gt;
必要なパーティションを切っていって、最後余った領域をスワップパーティションとして残しています。1つのハードディスクでせいぜい数GB程度であり、現在数百GBから1TBを越えるハードディスクが利用される現在では、数GBはハードディスク領域としては無視出来るサイズです。尚、複数のハードディスクにスワップ領域を分散させるのは、高速化を狙っているためです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Proc-swap-san.png|thumb|center|640px|自分のサーバのスワップ領域の状況]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : 近年ではSSDのような高速な外部記憶装置があるので、そもそもスワップ領域を分散させる必要性は小さいかも知れませんし、また分散させるとなるとハードディスク時代には手に入らなかったような高速なスワップ領域になるでしょう。&lt;br /&gt;
&lt;br /&gt;
== まとめ ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
簡単にまとめると以下のようになります。&lt;br /&gt;
&lt;br /&gt;
* スワップの領域を確保することは必要です。&lt;br /&gt;
* アプリケーションや利用状況に関係なく汎用的に適切なスワップ領域サイズというものはありません。&lt;br /&gt;
* スワップ領域を決める時は慣用的なサイズで設定する場合が多いが、その根拠はきわめて曖昧です。&lt;br /&gt;
* 古典的なメモリ量の2倍のスワップ領域というのは、現在の大容量メモリ搭載時代では、あまり合理的な方法とはいえません。&lt;br /&gt;
* 複数のハードディスク上のパーティションを同時に利用する場合、個々のパーティションサイズは小さくとも総量としては大きい領域が確保できます。&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1771</id>
		<title>スワップの運用について考えてみる</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1771"/>
		<updated>2025-12-10T09:10:59Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* システムにおけるスワップ運用の私見 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== システムにおけるスワップ運用の私見 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのスワップ　～正確にはページフォルトですが～ は、どう運用すべきかを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずスワップが必要か、必要でないかといえばスワップ領域は必要です。&lt;br /&gt;
実メモリ（物理的なメモリ）は、プログラムのメモリ空間だけではなく、I/Oのキャッシュバッファとしても使われます。&lt;br /&gt;
プログラムが使わなくなったメモリ空間を抱えていて、一方でパフォーマンスのために必要なI/Oのキャッシュバッファが十分に確保できないのでは本末転倒です。使わなくなったメモリ空間をスワップに追い出すことができれば実メモリを有効に活用できることになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
古くから「メモリサイズの2倍か3倍のサイズを取る」というのが慣習的に行われています。&lt;br /&gt;
しかし、この数字はベストプラクティスであって、理論的背景があって決められている数字ではありません。&lt;br /&gt;
一律の値ではなく、稼働させるアプリケーションと搭載メモリ量、そしてハードディスク搭載容量に依存するのはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux (13.2. システムの推奨スワップ領域)[https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/8/html/managing_storage_devices/recommended-system-swap-space_getting-started-with-swap]&lt;br /&gt;
&lt;br /&gt;
* Solaris のシステム管理 (デバイスとファイルシステム) [http://docs.oracle.com/cd/E19253-01/819-0386/fsswap-31050/index.html スワップ空間の計画]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの例からわかるのは「4GBぐらいのメモリ量の場合は、同等なスワップ領域であるが十分なメモリ量がある場合、スワップ領域はメモリサイズよりもはるかに少ない。」&lt;br /&gt;
「もし256GBのメモリ量で3倍のサイズとなると750GBとなり、現状、大容量ハードディスクが安くなったからといっても大きな領域を必要となり、システムを圧迫する。」ということです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまり搭載しているメモリやハードディスクだけに着目して、スワップ領域のサイズを決定するのは、何か決定的な根拠があるわけではなく、ただこれくらいあれば良いだろうという目安程度の話になっていると考えられます。&lt;br /&gt;
あくまでも利用するマシンでどのようなアプリケーションがどのような形で動作し、また、どこまで耐えるのか、ということがポイントであり、汎用な最適なスワップ領域サイズの解はないともいえます。&lt;br /&gt;
&lt;br /&gt;
== 自分はどうしているか ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では私自身はどうしているかというと、搭載されているメモリ量ではなく、ハードディスクのパーティションを切る際に余った領域をスワップ領域に割り当てる方法を取っています。特定のスワップ領域のサイズをターゲットにして取っているわけではありません。&lt;br /&gt;
必要なパーティションを切っていって、最後余った領域をスワップパーティションとして残しています。1つのハードディスクでせいぜい数GB程度であり、現在数百GBから1TBを越えるハードディスクが利用される現在では、数GBはハードディスク領域としては無視出来るサイズです。尚、複数のハードディスクにスワップ領域を分散させるのは、高速化を狙っているためです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Proc-swap-san.png|thumb|center|640px|自分のサーバのスワップ領域の状況]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : 近年ではSSDのような高速な外部記憶装置があるので、そもそもスワップ領域を分散させる必要性は小さいかも知れませんし、また分散させるとなるとハードディスク時代には手に入らなかったような高速なスワップ領域になるでしょう。&lt;br /&gt;
&lt;br /&gt;
== まとめ ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
簡単にまとめると以下のようになります。&lt;br /&gt;
&lt;br /&gt;
* スワップの領域を確保することは必要です。&lt;br /&gt;
* アプリケーションや利用状況に関係なく汎用的に適切なスワップ領域サイズというものはありません。&lt;br /&gt;
* スワップ領域を決める時は慣用的なサイズで設定する場合が多いが、その根拠はきわめて曖昧です。&lt;br /&gt;
* 古典的なメモリ量の2倍のスワップ領域というのは、現在の大容量メモリ搭載時代では、あまり合理的な方法とはいえません。&lt;br /&gt;
* 複数のハードディスク上のパーティションを同時に利用する場合、個々のパーティションサイズは小さくとも総量としては大きい領域が確保できます。&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1770</id>
		<title>スワップの運用について考えてみる</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B9%E3%83%AF%E3%83%83%E3%83%97%E3%81%AE%E9%81%8B%E7%94%A8%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1770"/>
		<updated>2025-12-10T09:10:31Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* システムにおけるスワップ運用の私見 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== システムにおけるスワップ運用の私見 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのスワップ　～正確にはページフォルトですが～ は、どう運用すべきかを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずスワップが必要か、必要でないかといえばスワップ領域は必要です。&lt;br /&gt;
実メモリ（物理的なメモリ）は、プログラムのメモリ空間だけではなく、I/Oのキャッシュバッファとしても使われます。&lt;br /&gt;
プログラムが使わなくなったメモリ空間を抱えていて、一方でパフォーマンスのために必要なI/Oのキャッシュバッファが十分に確保できないのでは本末転倒です。使わなくなったメモリ空間をスワップに追い出すことができれば実メモリを有効に活用できることになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
古くから「メモリサイズの2倍か3倍のサイズを取る」というのが慣習的に行われています。&lt;br /&gt;
しかし、この数字はベストプラクティスであって、理論的背景があって決められている数字ではありません。&lt;br /&gt;
一律の値ではなく、稼働させるアプリケーションと搭載メモリ量、そしてハードディスク搭載容量に依存するのはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux 13.2. システムの推奨スワップ領域 [https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/8/html/managing_storage_devices/recommended-system-swap-space_getting-started-with-swap]&lt;br /&gt;
&lt;br /&gt;
* Solaris のシステム管理 (デバイスとファイルシステム) [http://docs.oracle.com/cd/E19253-01/819-0386/fsswap-31050/index.html スワップ空間の計画]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの例からわかるのは「4GBぐらいのメモリ量の場合は、同等なスワップ領域であるが十分なメモリ量がある場合、スワップ領域はメモリサイズよりもはるかに少ない。」&lt;br /&gt;
「もし256GBのメモリ量で3倍のサイズとなると750GBとなり、現状、大容量ハードディスクが安くなったからといっても大きな領域を必要となり、システムを圧迫する。」ということです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまり搭載しているメモリやハードディスクだけに着目して、スワップ領域のサイズを決定するのは、何か決定的な根拠があるわけではなく、ただこれくらいあれば良いだろうという目安程度の話になっていると考えられます。&lt;br /&gt;
あくまでも利用するマシンでどのようなアプリケーションがどのような形で動作し、また、どこまで耐えるのか、ということがポイントであり、汎用な最適なスワップ領域サイズの解はないともいえます。&lt;br /&gt;
&lt;br /&gt;
== 自分はどうしているか ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では私自身はどうしているかというと、搭載されているメモリ量ではなく、ハードディスクのパーティションを切る際に余った領域をスワップ領域に割り当てる方法を取っています。特定のスワップ領域のサイズをターゲットにして取っているわけではありません。&lt;br /&gt;
必要なパーティションを切っていって、最後余った領域をスワップパーティションとして残しています。1つのハードディスクでせいぜい数GB程度であり、現在数百GBから1TBを越えるハードディスクが利用される現在では、数GBはハードディスク領域としては無視出来るサイズです。尚、複数のハードディスクにスワップ領域を分散させるのは、高速化を狙っているためです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Proc-swap-san.png|thumb|center|640px|自分のサーバのスワップ領域の状況]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : 近年ではSSDのような高速な外部記憶装置があるので、そもそもスワップ領域を分散させる必要性は小さいかも知れませんし、また分散させるとなるとハードディスク時代には手に入らなかったような高速なスワップ領域になるでしょう。&lt;br /&gt;
&lt;br /&gt;
== まとめ ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
簡単にまとめると以下のようになります。&lt;br /&gt;
&lt;br /&gt;
* スワップの領域を確保することは必要です。&lt;br /&gt;
* アプリケーションや利用状況に関係なく汎用的に適切なスワップ領域サイズというものはありません。&lt;br /&gt;
* スワップ領域を決める時は慣用的なサイズで設定する場合が多いが、その根拠はきわめて曖昧です。&lt;br /&gt;
* 古典的なメモリ量の2倍のスワップ領域というのは、現在の大容量メモリ搭載時代では、あまり合理的な方法とはいえません。&lt;br /&gt;
* 複数のハードディスク上のパーティションを同時に利用する場合、個々のパーティションサイズは小さくとも総量としては大きい領域が確保できます。&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;diff=1769</id>
		<title>ファイルシステム</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;diff=1769"/>
		<updated>2025-12-10T08:27:52Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* JFS / ReiserFS / XFS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== ファイルシステムの構造 ==&lt;br /&gt;
&lt;br /&gt;
ここでのファイルシステムは、ファイルを管理するシステム全体のことをいっています。一方、ext2やext3といった下位レベルのレイヤのファイルシステムも同じファイルシステムと呼ぶが一般的です。&lt;br /&gt;
これは古典的なUNIXでは、1つのファイルシステムは下位レイヤレベルで1つの形式しか持っていなかったため問題はありませんでした。&lt;br /&gt;
ところが現在では下位レイヤにいろいろな種類のファイルシステムをもっています。&lt;br /&gt;
ですから、前後の文脈を理解しておかないとファイルシステムと全体を意味するファイルシステムと、下位レイヤのファイルシステムをうまく用語で区別できない状況にありますし、文中でもそうなり読んでいて混乱しやすいので注意してください。&lt;br /&gt;
&lt;br /&gt;
;補足&lt;br /&gt;
: 次の解説も大変役に立ちます。 &#039;&#039; Linux ファイルシステムの徹底調査, 階層化構造からの検討, IBM developerWorks &#039;&#039; ([http://www.ibm.com/developerworks/jp/linux/library/l-linux-filesystem/ リンク切れ]) ([https://developer.ibm.com/tutorials/l-linux-filesystem/ オリジナル英語版])&lt;br /&gt;
&lt;br /&gt;
=== ツリー構造 === &lt;br /&gt;
&lt;br /&gt;
Unixのファイルシステムは/を頂点にしたツリー構造です。Windows系のオペレーティングシステムでは  「C: (Cドライブ)」  といったようにハードウェアである「ドライブ」を意識した構造になっていますが、Unixでは「/」を頂点にしたツリー構造になっています。ディレクトリとはパソコンで言う所のフォルダです。ディレクトリがファイルの属性情報を知っています。ファイル自体はデータのみ入っています。UNIXにおいてのファイルは先頭から連続したバイト列になっています。この事に関して、私達の身の回りにあるコンピュータでは何の不思議もありませんが、むかしの大型汎用機のファイル構成はこのようになっていませんでした。UNIXが登場した当時としては、このような形式はUNIXの特徴でもあったのですが、今やあたりまえになってしまっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずは 「/ (ROOTと呼びます)」にどんなファイルやディレクトリがあるかコマンド ls で見てみましょう。オプション -F は名前の後ろにキャラクタをつけて、それがファイルなのかディレクトリなのか、あるいは他の属性を持つのかを表現してくれます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -F /&lt;br /&gt;
 bin/	dev/	 home/	  lost+found/  proc/  tmp/  vmlinuz@&lt;br /&gt;
 boot/	etc/	 initrd/  mnt/	       root/  usr/&lt;br /&gt;
 cdrom/	floppy/  lib/	  opt/	       sbin/  var/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
名前の後ろに/がついているのがディレクトリです。ファイルの後ろに@がついているのは[https://uc2.h2np.net/index.php/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0#.E3.83.8F.E3.83.BC.E3.83.89.E3.83.AA.E3.83.B3.E3.82.AF.E3.81.A8.E3.82.B7.E3.83.B3.E3.83.9C.E3.83.AA.E3.83.83.E3.82.AF.E3.83.AA.E3.83.B3.E3.82.AF シンボリックリンク]です。WindowsであればC:とかE:といったドライブ名で出てくるのでハードウェアを意識する構造になっていますが、UNIXはハードウェアとしてのハードディスクは意識しません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : Linuxの標準的ファイルシステム階層のスペック(Filesystem Hierarchy Standard)はLinuxファンデーションがドキュメント化しています。&amp;lt;ref&amp;gt;&lt;br /&gt;
Filesystem Hierarchy Standard, &#039;&#039;FHS 2.3 was released January 29, 2004.&#039;&#039;&lt;br /&gt;
http://refspecs.linuxfoundation.org/fhs.shtml&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 主要なディレクトリの意味&lt;br /&gt;
** /bin : システムに最小限必要なコマンド群&lt;br /&gt;
** /dev : デバイススペシャルファイル群&lt;br /&gt;
**  /home : 一般ユーザのディレクトリ&lt;br /&gt;
**  /lost+found : 破損したファイルの断片を退逃させる (これはファイルシステムが作成するものでLinuxのファイルシステム階層には含まれない）&lt;br /&gt;
**  /proc : システムの状況やパラメータをやり取りするファイルのように見せかけたインタフェース&lt;br /&gt;
**  /tmp : テンポラリディレクトリ&lt;br /&gt;
**  /boot : ブート時に使用するカーネルが入っている&lt;br /&gt;
**  /etc : 各種システム設定ファイルのディレクトリ&lt;br /&gt;
**  /root : ユーザrootのディレクトリ&lt;br /&gt;
**  /usr : システムに必要なディレクトリ群が入っているディレクトリ&lt;br /&gt;
**  /sbin : システム管理者に最低限必要なコマンド群&lt;br /&gt;
**  /lib : システムに最低限必要なライブラリ群&lt;br /&gt;
**  /var : ログファイルやスプールなど用のディレクトリ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
むかしのUNIXではディレクトリは特殊なファイルで、catをすると本当に中身を表示できました。現在ではディレクトリはファイルではなく、ディレクトリという特別なファイルシステム上のノード情報という位置付けになっています。これはUNIXのファイルシステムが抽象化されたレイヤ構造になったためです。&lt;br /&gt;
&lt;br /&gt;
=== ファイルシステムのマウント === &lt;br /&gt;
&lt;br /&gt;
MOでもUSBメモリでもハードディスクでも、あるいはファイルであってもブロックデバイスとみなせるものなら同じですが、話を単純化するために、ここではハードディスクということで話を勧めましょう。&lt;br /&gt;
&lt;br /&gt;
ファイルシステムとはファイルを管理するための仕組み全体を指します。ハーディスクのパーティションをext2やext3、あるいはそれ以外のファイルシステムの形式にフォーマットし、それをファイルシステムとしてマウントします。&lt;br /&gt;
&lt;br /&gt;
まずハードディスクのパーティションを設定し、各々のパーティション上にファイルシステムを構築し（フォーマットし）、そしてマウントします。コマンドdfを使うと、どのパーティションがどのディレクトリにマウントしているのかわかります。&lt;br /&gt;
このディレクトリをマウントポイントと呼びます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ df&lt;br /&gt;
Filesystem     1K-blocks     Used Available Use% Mounted on&lt;br /&gt;
(省略)&lt;br /&gt;
/dev/sda1         487634   261696    196242  58% /boot&lt;br /&gt;
/dev/sda2      201820928 11906896 179647588   7% /&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/dev/sda1はSATA(Serial ATA)インタフェースで接続され認識された最初のハードディスクの最初のパーティションのことです。sda2は2番目のパーティションを意味しています。&lt;br /&gt;
元々/dev/sd? (?はアルファベット1文字が入る）はSCSIインタフェースのためのブロックデバイス名でしたが、現在ではSCSIだけではなく、SATA(Serial ATA)インタフェース、あるいは同等なインタフェースで接続された場合/dev/sd?に割り当てられます。&lt;br /&gt;
例えばUSBメモリを使うときも/dev/sd?となります。下の例はUSBメモリを挿した時の状態です。このUSBメモリには &#039;&#039;HIRONOBU&#039;&#039; と名前を設定しています。&lt;br /&gt;
多くのディストリビューションのデフォルトでは /media/ユーザ名 の下に自動的にマウントします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/dev/sdg1                       3804348    375556   3215828  11% /media/hironobu/HIRONOBU&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; 補足&lt;br /&gt;
:  [[USBメモリをLinuxファイルシステムとして使う]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxでハードディスクに利用できるファイルシステムの種類にはext2、ext3、ext4、&lt;br /&gt;
JFS、XFS、ReiserFSなど色々な種類が使えます。&lt;br /&gt;
近年のディストリビューションではデフォルトのファイルシステムがext4というものが多いですが、&lt;br /&gt;
これらのファイルシステムは、それぞれ性能や機能に特徴があります。&lt;br /&gt;
ユーザの選択肢が広く、その選択をユーザにゆだねているのもまたLinuxの特徴です。&lt;br /&gt;
個々のファイルシステムの特徴に関しては後ほど説明します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう&lt;br /&gt;
: Linux以前のUnixも一つのオペレーティングシステムは主たるファイルシステムは1つだけでした。それは何故でしょう。&lt;br /&gt;
&lt;br /&gt;
ファイルシステムの構築とマウントは非常に簡単です。ハードディスクを指定してフォーマットし、それとマウントポイントとなるディレクトリへマウントするだけです。&lt;br /&gt;
&lt;br /&gt;
=== inode ===&lt;br /&gt;
&lt;br /&gt;
Unixのファイルシステムは&amp;quot;/&amp;quot;を頂点としたツリー構造で一意のファイルを指&lt;br /&gt;
定するにはファイルパスを使いますが、ではカーネルの中ではどう扱っている&lt;br /&gt;
のでしょうか?&lt;br /&gt;
&lt;br /&gt;
カーネル内部ではファイルの実体は/home/hironobu/text.txt というファイル&lt;br /&gt;
パスで管理しているのではなくinodeというノード番号を使って管理していま&lt;br /&gt;
す。しかしユーザ側からアクセスをするのはファイル名(正確にはファイルパ&lt;br /&gt;
ス名ですが)を指定しますので、inode番号を使ってアクセスするようなことは&lt;br /&gt;
できません。ls -iを使えばinode番号が表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -i *.txt&lt;br /&gt;
 540463 memo.txt        540446 section-4.txt   540452 section-8.txt&lt;br /&gt;
 540402 section-1.txt   540444 section-5.txt   &lt;br /&gt;
 540416 section-2.txt   540420 section-6.txt&lt;br /&gt;
 540443 section-3.txt   540447 section-7.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
inode番号はディレクトリ中にあるファイル名とinode番号を管理するデータ構造&lt;br /&gt;
struct dirent&lt;br /&gt;
&amp;lt;ref&amp;gt;https://github.com/torvalds/linux/blob/master/include/linux/dirent.h&amp;lt;/ref&amp;gt;&lt;br /&gt;
に格納されています。&lt;br /&gt;
カーネル内の関数nameiによりファイル名はinode番号に変換されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
inode番号を直接扱えばより効率的ではないかと思う人もいるかも知れません。&lt;br /&gt;
理屈を考えると大型汎用機のようにファイル資源を固定的に指定できるような&lt;br /&gt;
システムの方が、一度ファイル名からファイル資源を示すデータへ変換するよ&lt;br /&gt;
うなUnix流よりもコストが低いといえるでしょう。しかしこのコストは現在の&lt;br /&gt;
ハードウェア事情を勘案すると実にわずかなものです。一方で名前空間による&lt;br /&gt;
柔軟なファイル管理の方が議論の余地なくオペレーションのコストが低いと言&lt;br /&gt;
えるでしょう。かくしてトータルで考えるとファイル名で扱う方がコスト的に&lt;br /&gt;
有利なのです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: ここでオペレーティングシステムの「コスト」とは、システムが動作するコストだけではなくオペレーションも含んだコストであると認識してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
inode自体は&lt;br /&gt;
struct inode&lt;br /&gt;
&amp;lt;ref&amp;gt;https://github.com/torvalds/linux/blob/master/include/linux/fs.h&amp;lt;/ref&amp;gt;&lt;br /&gt;
を参照するとわかりますが、ファイルの属性に関する情報などを持っています。&lt;br /&gt;
一方でユーザはinode番号はわかりますがinodeが持っている情報には直接アク&lt;br /&gt;
セスできません。&lt;br /&gt;
ファイルのユーザ属性を変えたり、あるいは情報を獲得するにはchmod(2)、stat(2)と&lt;br /&gt;
いったシステムコール経由でアクセスするしかありません。&lt;br /&gt;
これはLinuxのような今日的なUnix系のオペレーティングシステムでは、&lt;br /&gt;
複数のファイルシステムの方式を同時に持っているからです。&lt;br /&gt;
&lt;br /&gt;
=== VFS ===&lt;br /&gt;
[[File:Filesystem-layer-1.png‎|thumb|right|300px|VFSレイヤ概念図]]&lt;br /&gt;
複数のファイルシステム方式があるのに、何故ユーザは統一したインタフェースでファイルにアクセスできるのでしょう? &lt;br /&gt;
それはVFS (Virtual File System)&lt;br /&gt;
&amp;lt;ref&amp;gt;VFSに関する資料 https://developer.ibm.com/tutorials/l-virtual-filesystem-switch/&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;ref&amp;gt;Overview of the Linux Virtual File System https://www.kernel.org/doc/html/latest/filesystems/vfs.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
が用意されているからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
VFSは個々のファイルシステムとユーザの間のクッションの役目を果たしており、&lt;br /&gt;
ユーザ側からはVFSしか見えないようになっています。&lt;br /&gt;
このVFSがファイルシステム間の違いを吸収し、統一したインタフェースをユーザ側に提供します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
むかしむかしのUNIXはディレクトリとファイルのアクセスの違いはありませんでした。&lt;br /&gt;
ディレクトリはシステムがファイルを管理するための内容を持ったファイルでしかありませんでした。&lt;br /&gt;
ファイルシステムが1種類しかなく自分のマシンに接続するハードディスク上にあった頃は、&lt;br /&gt;
これでも十分ですが、複数のファイルシステムが存在する場合はそうもいきません。&lt;br /&gt;
機能や仕様が個々に違う、すべてのファイルシステムに同じ方法でアクセスすることを提供しなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイルシステムの上に仮想的なファイルシステムを加えて統一したインタフェースを提供するようになったのは1984年のSUN MicrosystemsがSunOS 2.0が最初です。&amp;lt;ref&amp;gt;Jim Mauro and Richard McDougall, &amp;quot;Solaris Internals: Core Kernel Components&amp;quot;, Prentice Hall Professional, 2001&amp;lt;/ref&amp;gt;&lt;br /&gt;
色々なファイルシステムを扱えるフレームワークは、Sunが開発した NFS(Network File System) が別のマシン上にあるファイルシステムをネットワーク経由でマウントするために必要でした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
VFSの下に位置するファイルシステムは、少なくともカーネルのソースコードで数えた所、50以上ありました。&lt;br /&gt;
&amp;lt;ref&amp;gt;https://github.com/torvalds/linux/tree/master/fs&amp;lt;/ref&amp;gt;&lt;br /&gt;
個々のファイルシステムがどこまで利用可能なのか、つまり、常用のファイルシステムとして使えるのか、&lt;br /&gt;
互換性のために残しているのか、あるいは読み込みだけで書き込みができない、&lt;br /&gt;
あるいは一部の機能しか使えないなどに関しての資料が見当たらないので一概に50以上というのは不適切かも知れません。&lt;br /&gt;
しかし、数種類、あるいは十数種類というレベルではないことは確かです。&lt;br /&gt;
&lt;br /&gt;
次に主要なファイルシステムを取り上げて説明します。&lt;br /&gt;
&lt;br /&gt;
== ファイルシステム ==&lt;br /&gt;
&lt;br /&gt;
ここでは下位レイヤでのファイルシステムを個別に説明します。&lt;br /&gt;
&lt;br /&gt;
その前に、現在利用しているGNU/Linuxのシステムがどのようなファイルシステムをサポートしているのかを確認する時は [[/proc/filesystems]] を参照するとわかります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cat /proc/filesystems&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ext2 ファイルシステム ===&lt;br /&gt;
&lt;br /&gt;
ext2ファイルシステム&lt;br /&gt;
&amp;lt;ref&amp;gt;ext2に関する資料&lt;br /&gt;
http://www.linux.or.jp/JF/JFdocs/Filesystems-HOWTO-6.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
は正式名称Second Extented Filesystemといい、ext2fs とも書きます。Linux のために開発されたファイルシステムです。&lt;br /&gt;
前身である Ext ファイルシステムの次のバージョンと位置づけられます。&lt;br /&gt;
現在も /boot のファイルシステムは ext2 ファイルシステムを利用しているディストリビューションが多くあります。&lt;br /&gt;
最大ファイルシステムサイズ4TB (カーネル2.6からは32TB)、最大ファイルサイズ2GB まで扱えます。&lt;br /&gt;
&lt;br /&gt;
ext2ファイルシステムはファイルの読み書きで良い局所性を出すための工夫がされています。&lt;br /&gt;
書き出しが行われる時、同じブロックグループ内で、隣接する8ブロックを先行して割り当てするので、連続しての書き込みの効率があがります。&lt;br /&gt;
このような書き方をするので当然、連続しての読み込みをする際のヒット率が高くなります。&lt;br /&gt;
&lt;br /&gt;
=== ext3 ファイルシステム === &lt;br /&gt;
&lt;br /&gt;
ext3&lt;br /&gt;
&amp;lt;ref&amp;gt;ext3に関する資料 http://www.valinux.co.jp/docs/pdf/D-3.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
ext2 をベースにジャーナリングファイルシステム(Journaling Filesystem)に拡張したものです。&lt;br /&gt;
ジャーナリングファイルシステムとはメタデータと呼ばれるファイル属性などの変更履歴をジャーナルログに記録しておき、ファイルシステムの整合をチェックする時は、そのジャーナルを使う方式です。&lt;br /&gt;
ext2 ファイルシステムのように整合性をチェックするためにファイルシステム全部を走査する必要がないので高速に処理ができます。&lt;br /&gt;
最大ファイルシステムサイズ4TB、最大ファイルサイズ4TBまで扱えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ext4 ファイルシステム ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ext4 は ext3 の後継として作られたファイルシステムです。カーネル2.6.19 から正式採用しています。ext4 のファイルシステムは1EB、ファイルサイズは16TBのサイズをサポートしています。&lt;br /&gt;
&lt;br /&gt;
同時期に存在していた競合していたJFSやXFSファイルシステムから良い点を導入しするなど新しい機能や拡張を行い、また安定性も十分に備え、ext3に比べて大きく進化しています。&lt;br /&gt;
&lt;br /&gt;
たとえばパフォーマンスに関してはブロックの遅延アロケーションが可能になりました。これはなるべくディスク上の物理ブロックを連続に確保するために書き込みを遅滞させます。連続した物理ブロックに書き込むことが出来るようになり、その後にファイルをリードする際に高速に読み込むことが出来るようになります。ファイルサイズが最初にわかっている場合はファイルのプリアロケーションの機能を使いディスク上の物理ブロックを予め確保することが出来ます。&lt;br /&gt;
&lt;br /&gt;
他にもたくさんの新しい機能があります。調べるには下記の資料が役に立つでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* RED HAT ENTERPRISE LINUX ストレージ管理ガイド [https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/storage_administration_guide/ch-ext4 第6章 EXT4 ファイルシステム]&lt;br /&gt;
&lt;br /&gt;
* AAnatomy of ext4　[https://developer.ibm.com/tutorials/l-anatomy-ext4/ Anatomy of ext4 ]&lt;br /&gt;
&lt;br /&gt;
=== JFS / ReiserFS / XFS ===&lt;br /&gt;
&lt;br /&gt;
ext4と比べるべきファイルシステムとして過去IBM社が開発しLinuxカーネルにマージされているJFSファイルシステム&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
JFS&lt;br /&gt;
https://wiki.archlinux.jp/index.php/JFS&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
、&lt;br /&gt;
ReiserFS ファイルシステム、&lt;br /&gt;
あるいは過去シリコングラフィックス社が開発しLinuxカーネルにマージされているXFSファイルシステム&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
http://xfs.org/index.php/Main_Page&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
などもあります。&lt;br /&gt;
これらはいずれもジャーナリング機能を持っており、かつ、特色ある機能を持っています。&lt;br /&gt;
&lt;br /&gt;
JFS は IBM の AIX、&lt;br /&gt;
XFS はシリコングラフィックス社の IRIX といった実績のあるUNIX系OSで使われていたものであり、&lt;br /&gt;
それが Linux に移植され利用されるに至っています。&lt;br /&gt;
JFS にしても XFS にしても、これらの能力を最大限に生かしきるのはサーバやクラスタといったエンタープライズ環境であり、&lt;br /&gt;
熟練オペレーターによる運用が行われる場合、これらのエンタープライズ環境で必須な障害からの復帰などの能力や特性を十分に活かすことが出来るでしょう。&lt;br /&gt;
&lt;br /&gt;
; 補足 : 常用デスクトップのレベルであれば、多くのGNU/Linuxディストリビューションが採用しているext4で十分な性能を保つことができます。&lt;br /&gt;
&lt;br /&gt;
=== Reiser4 / NILFS2 / Btrfs  === &lt;br /&gt;
&lt;br /&gt;
JFSやXFSやReiserFSの次の世代のファイルシステムです。&lt;br /&gt;
&lt;br /&gt;
* Reiser4 : ReiserFSの後継。まったくの別実装。&lt;br /&gt;
* NILFS2 : Log-structured ファイルシステム、耐故障性の向上、スナップショット機能&lt;br /&gt;
* Btrfs : 耐故障性の向上、多機能&lt;br /&gt;
&lt;br /&gt;
(TBD)&lt;br /&gt;
&lt;br /&gt;
=== ISO9660 ファイルシステム === &lt;br /&gt;
&lt;br /&gt;
CDROMの規格であるISO9660のファイルシステムです。このファイルシステムを&lt;br /&gt;
指定してマウントすると、CDROM (もちろんISO9660であること) をリードオン&lt;br /&gt;
リーのファイルシステムと認識されます。類似のファイルシステムにJPLIETファ&lt;br /&gt;
イルシステムやZISOFSファイルシステム、DVD用のUDFなどもなどもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== tmpfs、ramfsファイルシステム ===&lt;br /&gt;
&lt;br /&gt;
メモリ上に展開するファイルシステムです。メモリ上にあるのでシステムが停止すればなくなります。一時的なファイルを作成するファイルシステムとして利用されます。tmpfsは仮想記憶上に取られるので利用するシステムの記憶領域が足りない時はページイン・ページアウトが発生します。&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : dfやmountコマンドを使って、自分のファイルシステムでtmpfsがどのように使われているか調べてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
その他にもLiveCDのようにハードディスクを使えないような場合に、メモリ上にファイルシステムを構築する際に利用されます。&lt;br /&gt;
&lt;br /&gt;
; 補足 : ramfsは物理的メモリしか使わないのに対し、tmpfsは仮想記憶上に取られます。つまりtmpfsは、システムの物理的記憶空間が足りなくなってきた場合、内容をスワップします。そのため、搭載している物理的メモリよりも大きなエリアを取ることも可能です。&lt;br /&gt;
&lt;br /&gt;
=== JFFS / JFFS2  ===&lt;br /&gt;
&lt;br /&gt;
USBストレージやSDカードなどフラッシュメモリを使った記憶装置をファイルシステムとして使うためのフラッシュ・ファイルシステムがLinuxには用意されています&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux フラッシュ・ファイルシステムの徹底調査 さまざまな選択肢とそのアーキテクチャー&lt;br /&gt;
https://www.ibm.com/developerworks/jp/linux/library/l-flash-filesystems/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
。&lt;br /&gt;
フラッシュ・ファイルシステムとして&lt;br /&gt;
JFFS (Journaling Flash File System)、 &lt;br /&gt;
JFFS2 (Journaling Flash File System 2)、&lt;br /&gt;
YAFFS2 (Yet Another Flash File System 2)&lt;br /&gt;
などがあります。&lt;br /&gt;
JFFSは現在では使われておらず、後継のJFFS2が利用されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
フラッシュメモリ(ここではUSBストレージやSDカードに使われているNAND フラッシュ･デバイスとします)には書き込みや読み込みはハードディスクと違う動作を必要としますし、またフラッシュメモリには書き換え上限があり同じ場所で書き込みを繰り返し上限に達すると、その場所が書き込めなくなるります。そのためフラッシュメモリに特化したファイルシステムが用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一方で近年ではSDカードやUSBストレージのハードウェアも進化し特別なファイルシステムがなくとも効率よく、かつ寿命が伸びる仕組みを取り入れているのでSDカードやUSBストレージを使っているからといって必ずJFFS2のようなファイルシステムが必要であるというわけではない状況になって来ています。たとえばAndroidの場合、古くはJFFS2でしたが後にext4に切り替えています。&lt;br /&gt;
&lt;br /&gt;
=== ネットワークファイルシステム === &lt;br /&gt;
&lt;br /&gt;
==== NFS ====&lt;br /&gt;
NFS (Network filesystem) はUnixで最初に使われたネットワークを経由してファイルシステムをマウントする仕組みです。&lt;br /&gt;
NFSの仕様はUNIXだけではなく抽象化したファイルシステムとなっています。&lt;br /&gt;
たとえば異なるUnixの種類同士&lt;br /&gt;
(例えばFreeBSDのファイルシステムとLinuxとか、あるいはSUN SolarisとSystemV IIIとか)、&lt;br /&gt;
あるいはUnixとWindowsといったファイルシステムの種類の異なるものでもネットワークを介して共有することができます。&lt;br /&gt;
LANで接続されたコンピュータ間でファイルを共有することを想定しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== CODA ====&lt;br /&gt;
&lt;br /&gt;
CODA&lt;br /&gt;
&amp;lt;ref&amp;gt;CODAのウェブサイト&lt;br /&gt;
http://www.coda.cs.cmu.edu/&amp;lt;/ref&amp;gt;&lt;br /&gt;
はNFSと同様にネットワークを経由してファイルを共有する仕組みです。&lt;br /&gt;
NFSは古典的なUnixのファイルシステムをネットワーク上に延長してきたとい&lt;br /&gt;
えますが、CODAはネットワークがまずありきの設計になっています。モバイル&lt;br /&gt;
コンピュータでも使えるようにネットワークが切り離されても動きますし、サー&lt;br /&gt;
バの複製などもできます。かなり近代的かつ、使い勝手が良いシステムに出来&lt;br /&gt;
上がっています。&lt;br /&gt;
&lt;br /&gt;
==  ハードリンクとシンボリックリンク ==&lt;br /&gt;
&lt;br /&gt;
さて予備知識が必要なために、少々後回しになりましたがハードリンクとシンボリックリンクの話を始めます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ある名前を付けられたシンボリックリンクはファイルのように見え、読み書き&lt;br /&gt;
などができます。しかし、シンボリックリンク自体は実体を持たず、名前で別&lt;br /&gt;
のファイルを参照しています。Windows XPなどのショートカットと同じような&lt;br /&gt;
ものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ハードリンクはファイル名で既にアクセスする実体を、他のファイル名でもア&lt;br /&gt;
クセスできるようにする仕組みといった方がいいかも知れません。ここでの実&lt;br /&gt;
体、つまりinode で参照できるファイルの内容です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この違いは、シンボリックリンクをしている先のファイルを消すのと、ハード&lt;br /&gt;
リンクしている先のファイルを消すにわかります。シンボリックリンクの先の&lt;br /&gt;
ファイルを消してみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ echo &#039;abcd&#039; &amp;gt; i&lt;br /&gt;
 $ cat i&lt;br /&gt;
 abcd&lt;br /&gt;
 $ ln -s i t&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 4&lt;br /&gt;
 -rw-r--r--  1 hironobu hironobu 5 2005-11-21 20:12 i&lt;br /&gt;
 lrwxrwxrwx  1 hironobu hironobu 1 2005-11-21 20:12 t -&amp;gt; i&lt;br /&gt;
 $ cat t&lt;br /&gt;
 abcd&lt;br /&gt;
 $ rm i&lt;br /&gt;
 rm: remove 通常ファイル `i&#039;? y&lt;br /&gt;
 $ cat t&lt;br /&gt;
 cat: t: そのようなファイルやディレクトリはありません&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイルiをシンボリックリンクしているtは、ファイルiが存在しないとtを参&lt;br /&gt;
照しても、ファイルが存在しないとなりエラーとなります。次はハードリンクです。ハードリンクはiを消してもファイルの実体をtが指し&lt;br /&gt;
ているので、ファイルの中身はまだ存在しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ echo &#039;abcd&#039; &amp;gt; i&lt;br /&gt;
 $ ln i t&lt;br /&gt;
 $ ls -li&lt;br /&gt;
 合計 8&lt;br /&gt;
 -rw-r--r--  2 hironobu hironobu 5 2005-11-21 20:14 i&lt;br /&gt;
 -rw-r--r--  2 hironobu hironobu 5 2005-11-21 20:14 t&lt;br /&gt;
 $ ls -li&lt;br /&gt;
 合計 8&lt;br /&gt;
 8488913 -rw-r--r--  2 hironobu hironobu 5 2005-11-21 20:14 i&lt;br /&gt;
 8488913 -rw-r--r--  2 hironobu hironobu 5 2005-11-21 20:14 t&lt;br /&gt;
 $ rm i&lt;br /&gt;
 rm: remove 通常ファイル `i&#039;? y&lt;br /&gt;
 $ cat t&lt;br /&gt;
 abcd&lt;br /&gt;
 $ ls -il&lt;br /&gt;
 合計 4&lt;br /&gt;
 8488913 -rw-r--r--  1 hironobu hironobu 5 2005-11-21 20:14 t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
lsコマンドの i オプションはinode番号の表示です。lsコマンドの表示の最初&lt;br /&gt;
8488913がinode番号です。パーミッション&amp;quot;-rw-r--r--&amp;quot;の後の数字は、ファイ&lt;br /&gt;
ル実体への参照リンク数を表しています。最初のiとtがある時は、その実体を&lt;br /&gt;
参照している数は2です。ファイルiを消すと、数が減るので1になります。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1768</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1768"/>
		<updated>2025-10-30T06:26:26Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* プロセスの基本的概念 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  ベイリー＝ボールウェイン＝プラウフ法で円周率の計算をおこなうプログラム https://uc2.h2np.net/src/mt-bbp.c&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下10万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、十数分、あるいはもっと長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;追記: その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
==== スケジューラのチューニング ====&lt;br /&gt;
&lt;br /&gt;
スケジューラのチューニングに関しては下記の情報が参考になります。&lt;br /&gt;
&lt;br /&gt;
* SUSE [https://www.belbel.or.jp/opensuse-manuals_ja/cha-tuning-taskscheduler.html タスクスケジューラのチューニング]&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux 9 [https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/pdf/monitoring_and_managing_system_status_and_performance/red_hat_enterprise_linux-9-monitoring_and_managing_system_status_and_performance-ja-jp.pdf 第30章 スケジューリングポリシーの調整]&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が低く、大きいものが実行優先順位が高くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1767</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1767"/>
		<updated>2025-10-30T06:22:14Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* プロセスの基本的概念 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  ベイリー＝ボールウェイン＝プラウフ法で円周率の計算をおこなうプログラム https://uc2.h2np.net/src/mt-bbp.c&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下3300万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、数十分、あるいは数時間という具合に長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;追記: その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
==== スケジューラのチューニング ====&lt;br /&gt;
&lt;br /&gt;
スケジューラのチューニングに関しては下記の情報が参考になります。&lt;br /&gt;
&lt;br /&gt;
* SUSE [https://www.belbel.or.jp/opensuse-manuals_ja/cha-tuning-taskscheduler.html タスクスケジューラのチューニング]&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux 9 [https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/pdf/monitoring_and_managing_system_status_and_performance/red_hat_enterprise_linux-9-monitoring_and_managing_system_status_and_performance-ja-jp.pdf 第30章 スケジューリングポリシーの調整]&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が低く、大きいものが実行優先順位が高くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1766</id>
		<title>オペレーティングシステムとは何か</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1766"/>
		<updated>2025-07-23T04:09:33Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 2007年現在の状況 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== オペレーティングシステムとは何か == &lt;br /&gt;
&lt;br /&gt;
===  オペレーティングシステムの再確認 === &lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムとは何かを基本に戻って再確認してみましょう。&lt;br /&gt;
オペレーティングシステム( Operating System )を短く説明すれば、文字通りコンピュータを操作してゆく&lt;br /&gt;
(Operating/オペレーティング)&lt;br /&gt;
体系&lt;br /&gt;
(System/システム)&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの役目は次の３つの目標を達成するためにリソース&lt;br /&gt;
(Resources : 資源 )&lt;br /&gt;
と、&lt;br /&gt;
アプリケーション&lt;br /&gt;
( Applications : ユーザが使うソフトウェア )&lt;br /&gt;
の間に存在し両者を結び付けるための糊の役目をするソフトウェア群であるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* リソースを効率的に利用し、また管理をする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションが直接リソースを制御する必要をなくする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションにとってリソースをさらに抽象化する&lt;br /&gt;
&lt;br /&gt;
=== リソースとは === &lt;br /&gt;
&lt;br /&gt;
リソースとは、コンピュータ上にある、処理を行なう際に必要となる資源を意味する概念的なものです。&lt;br /&gt;
リソースとしてハードウェアリソースとソフトウェアリソースの2つはすぐに思い浮かぶでしょう。&lt;br /&gt;
さらに一歩踏み込んでオペレーティングシステムはコンピュータ・システムを利用するコストをより少なくするための道具と考えるならば、&lt;br /&gt;
利用者や運用者などを指してヒューマンリソースとしリソースの中に含める必要が出てきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまりハードウェアリソース、ソフトウェアリソース、ヒューマンリソースを有効に使うための役割がオペレーティングシステムには求められます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 捕捉 :  一口にコストといってもいろいろな場面でのコストがあります。また数値に現れるコストだけではなく、数値に現れにくく把握するのが難しいコストもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下に色々なリソースについて考えてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ハードウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ハードウェアリソースにはCPU、主記憶装置(メモリ）、補助記憶装置、入出力装置、ほかがあります。&lt;br /&gt;
&lt;br /&gt;
===== CPU =====&lt;br /&gt;
&lt;br /&gt;
CPU( Central Processing Unit : 中央演算処理装置 ) : 命令を実行し、演算を行なうユニット部分です。少し前までは、CPUの説明といえば、プロセッサチップを示せば終だったのですが、最近の高性能のプロセッサチップは、少々複雑になっています。現在のプロセッサチップは、キャッシュ記憶ユニットという高速に記憶を取り込むための、短期間だけ記憶を保持しているような記憶装置も内蔵しています。それ以外にも多くの機能を詰め込んでいます。そこまで分割していくと話が混乱しますので、ここでのCPU はプロセッサチップという具体的な製品ではなく、命令を実行し演算を行なうユニットという抽象的な役割部分だと理解してください。以降、他のCPU説明でも同じです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 主記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
主記憶装置 ( Main Memory Unit ) : いわゆるメモリのことです。&lt;br /&gt;
CPUと直接やりとりする記憶装置を指します。&lt;br /&gt;
演算のための値を記憶しておく、結果を記憶しておく、命令を記憶しておくなどといったために使われます。&lt;br /&gt;
以前は、単純にCPU ←→主メモリという構造で説明が十分だったのですが、現在での具体的な物理メモリの構成は、アクセスの効率を考え何段階かの動作速度や容量が異なるキャッシュメモリを用意しておき、CPUと記憶をやりとりしています。&lt;br /&gt;
わりきって一言でいうなら電気を切ったら消えてしまう一時的な記憶装置だといえます。&lt;br /&gt;
&lt;br /&gt;
===== 補助記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
補助記憶装置 ( Auxiliary Memory Unit ) : ハードディスクや磁気テープのような装置のことです。&lt;br /&gt;
現在ではコンパクトフラッシュメモリやUSBメモリなどもこのような区分けに入ってきます。&lt;br /&gt;
主記憶装置との違いは、CPUと直接記憶のやりとりを行なわないこと、記憶の容量が大きいこと、長期間記憶&lt;br /&gt;
(わり切って言えば電気を切っても消えない記憶)&lt;br /&gt;
を保持するユニットです。&lt;br /&gt;
&lt;br /&gt;
===== 入出力装置 =====&lt;br /&gt;
&lt;br /&gt;
入出力装置 ( Input/Output Unit ) : キーボード、マウス、ディスプレイといったものや、シリアルポートやパラレルポート、またあるいはネットワークボードといったものなどのがあげられます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:  ハードウェアリソースを構成&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 上 , ジョン・L. ヘネシー (著), デイビッド・A. パターソン (著), 成田 光彰 (翻訳), 2014/12/6, ISBN 4822298426&lt;br /&gt;
&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 下, デイビッド・A・パターソン (著), ジョン・L・ヘネシー (著), 成田光彰 (翻訳), 2014/12/6, ISBN 4822298434&lt;br /&gt;
&amp;lt;/ref&amp;gt;するものとしてこの他に、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
====  ソフトウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ソフトウェアは、そのコンピュータ上で動くソフトウェアで共有し利用するようなデータ、ライブラリ、プログラムを意味します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばオペレーティングシステムの心臓部である[[カーネルの構造と機能|カーネル部分]]、アプリケーションが使うライブラリ、あるいはシステムを運用する上で必要なコマンド群などがあげられます。データベースを考えるとアプリケーションとしてのデータベースプログラムとその中に格納されアプリケージョンに利用されるデータから成り立ちます。この両者があってソフトウェアリソースとして提供されるデータベースとして意味をなします。多種多様なソフトウェアリソースがどのような役割を担うのかの議論は後ほどしましょう。&lt;br /&gt;
&lt;br /&gt;
==== ヒューマンリソース ====&lt;br /&gt;
&lt;br /&gt;
人的なリソースです。コンピュータが非常に高価だった頃は、その利用のために人を雇うコストの方が小さいファクタだったため、あまり大きな関心は寄せられていませんでした。&lt;br /&gt;
昔の汎用機時代においては、人的コストよりもハードウェアのコストの方がはるかに高く、そのため人間が便利に使えるよりも、まずハードウェアを最も効率よく使うにはどうするべきかを優先していたのです。&lt;br /&gt;
高性能のコンピュータがコモディティ(日用品)化してしまっている現在では、人的なリソースの方が高価です。人的リソースの効率的利用できるようにすることもオペレーティングシステムには求められています。このように時代の流れでハードウェアのコストが下がるにつれ、人的コストの比率が相対的にあがってきます。このような状況では、今度は人的コストを如何に下げるかが今日の課題となっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039; : 人的なコストを低減するためにどのような工夫がなされているのだろうか。&lt;br /&gt;
&lt;br /&gt;
== オペレーティングシステムの潮流 ==&lt;br /&gt;
&lt;br /&gt;
時が立つにつれ、どんどんハードウェアが小型化し、また高性能になっていきます。&lt;br /&gt;
例えば、2010 年のデスクトップコンピュータ、いわゆるパソコンと呼ばれる機械の上位機種の計算スピードは、私がこの業界に入った 1980 年半ばのスーパーコンピュータ並、あるいはそれ以上の性能を持っています。この文章を読んでいるこの瞬間では、2010年のデスクトップパソコンなど性能的に時代遅れになっているでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1990 年当時から比較しても、エンジニアリングワークステーションと呼ばれていた数百万から一千万円くらいの価格だったコンピュータシステムよりも遥かに高速です。&amp;lt;ref&amp;gt;RASPBERRY PI 2 MODEL B http://www.raspberrypi.org/products/raspberry-pi-2-model-b/ &amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Iridis-pi: a low-cost, compact demonstration cluster https://www.southampton.ac.uk/~sjc/raspberrypi/raspberry_pi_iridis_lego_supercomputer_paper_cox_Jun2013.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
当然、そうなってくると、高性能なハードウェアを効率よく動かす、かつハードウェアの能力を引き出すために、かつて高価なコンピュータで使われたいたオペレーティングシステムのテクノロジーが必要になってきます。かくして、身近に高性能なオペレーティングシステム が使われるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 現在のオペレーティングシステムへ向かう2つの流れ ===&lt;br /&gt;
&lt;br /&gt;
現在のハードウェアとオペレーティングシステムの関係をハードウェアの歴史の変遷を踏まえて考えてみます。みなさんが使っているデスクトップのコンピュータに至る流れには2つの流れがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 下から上への流れ ====&lt;br /&gt;
&lt;br /&gt;
小さいものから、大きなものへ変化した様子を見てみましょう。&lt;br /&gt;
1971年に世界初のマイクロプロセッサIntel 4004 が出来てから、パーソナルコンピュータが作られ、どんどん性能が良くなってきた流れです。パーソナルコンピュータ、いわゆるパソコンは初めは玩具のようなものでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1975年に発売された世界初のパソコンMITS Altair 8080はIntel 8080 250Khz を搭載しメモリは256byteでした。キーボードもモニターも当然ながらハードディスクなどありません。プログラムはフロントパネルからスイッチを操作し、バイナリーのマシン語を入力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1976年ぐらいになると、Apple、Sol、Altairといった最も初期の頃のパソコンが作られてきます。この頃、Bill GatesとPaul AllenはAltair 8080 (メモリ4KByte版）用に大型汎用機上で動いていたBASIC言語を移植しMITSへライセンスします。翌、1977年には [[Steve Wozniak]] とSteve Jobs &amp;lt;ref&amp;gt; スティーブ・ジョブズ 1 (講談社+α文庫)  ISBN 4062816148 &amp;lt;/ref&amp;gt;がApple Corporationを設立し、また同じくしてBill Gates とPaul Allenは正式にMicrosoft companyを設立します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Apple や Sol や Altairのような初期のパソコンが作られます。スミソニアン博物館にある初期のパソコンたちの写真です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2551.JPG|thumb|220px|Homebrew computer club ]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2548.JPG|thumb|220px|Apple]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2549.JPG|thumb|220px|Sol]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2547.JPG|thumb|220px|Altair]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1984年にIBMがIBM PCを販売開始した時が、今日のパーソナルコンピュータ隆盛の時代の本格的な幕開けだったといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
初期の頃のパソコンにはオペレーティングシステムがありませんでした。次にCP/MやMS-DOSといった 低レベルな機能しか持たない原始的なオペレーティングシステムが現われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 機能が不十分なため厳密にはオペレーティングシステムとは呼べずモニターと呼ぶべきものだと筆者は考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:オペレーティングシステムの前段階ともいえるモニターとはなんだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはハードウェアの能力が極めて限られているので、大型汎用機のような機能を望むべくもなく、低レベルな機能しか持たざる得ないという限界があります。1990年代ともなると、高速なCPU、大容量のメモリー、大容量のハードディスクなどハードウェアの能力は格段に上がります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、一方で、そのハードウェア上で動かしているソフトウェアのシステム構造は古い頃から手直しを繰り返してアップグレードしてきたものです。さらにパーソナルな環境ではなく、ネットワークに繋がれ、さらにはインターネットに繋がれるまでになると、玩具の箱から個人のツールとして発展してきた単純なパーソナルコンピュータのモデルではいずれ限界が来てしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように下から上へ向かうトレンドが、まず1つあります。&lt;br /&gt;
&lt;br /&gt;
==== 上から下への流れ ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コンピュータが作られた時から、今日のパーソナルコンピュータが隆盛を究めるまでに至まで常にコンピュータのハードウェアは高価なものでした。&lt;br /&gt;
1960年当時初期までは、コンピュータはプログラムを走らせるために特別なセットアップが必要で、色々なプログラムを走らせることが困難でした。&lt;br /&gt;
高価なハードウェア上でもっと汎用的にプログラムを動かすために作られたシステムが1964年に作られたIBM S/360です。ここで始めて今日的なオペレーティングシステムが作られます。&lt;br /&gt;
汎用機という言葉は、この「汎用的にプログラムを動かすことができるシステム」という所から来ています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:NASAComputerRoom7090.NARA.jpg|left|thumb|300px| 1962年にNASAで使われていた IBM 7090 の写真(NASAサイトより)&amp;lt;ref&amp;gt;NASA の著作権ポリシー http://www.jsc.nasa.gov/policies.html#Guidelines&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
時代は流れ大型汎用機もダウンサイジングの流れには逆らえませんでした。&lt;br /&gt;
まず最初のダウンサイジングで成功したのはDEC社の科学技術計算用コンピュータPDPシリーズやVAXシリーズです。&lt;br /&gt;
これらはミニコンと呼ばれました。これは1970年代後半から80年代後期まで成功を納めます。&lt;br /&gt;
さらに時代は進み、今度はワークステーションの出現です。&lt;br /&gt;
90年代に入るとDEC社のVAXが、SUN MicrosystemsのSUN ワークステーションに置き換わることになります。&lt;br /&gt;
そのダウンサイジングに大きな役目を果たしたのがUNIXです。&lt;br /&gt;
UNIXはワークステーションからスーパコンピュータまであらゆるサイズのコンピュータ上で使えるようになっていました。&lt;br /&gt;
別の言い方をすれば、ワークステーションからスーパーコンピュータでも十分に満足できる今日的オペレーティングシステムの機能をUNIXは兼ね備えているというわけです。&lt;br /&gt;
しかし、まだ業務や科学技術計算で使うコンピュータと、パーソナルで使うコンピュータには価格的にも性能的にも大きな隔たりがありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代後半になるとIA-32 (&#039;&#039;Intel Architecture,32bit&#039;&#039;)のハードウェアに席捲されます。2000年以降は、ダウンサイジングの到着点です。もう個人で使うパーソナルコンピュータも、業務や科学技術計算で使うものも、ハードウェア的には価格的にも、使われている技術にも、処理能力にも線引きが出来できません。2005年では、64bit CPU、デュアルプロセッサ対応、デュアルコアCPUといった最先端のテクノロジーがコモディティ市場 (一般消費者向け市場) に売られている時代になりました。この傾向はこれから先も続きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 考えてみよう : ムーアの法則とは限界を示しているのか、いないのか。限界を示しているとしたらなぜなのか。あるいは、ないならばなぜなのか。尚、ムーアの法則の意味は、オリジナルの意味である集積度の向上と、派生的に多く使われている性能の向上のどちらの意味で取ってもよい。&lt;br /&gt;
&lt;br /&gt;
===  2007年現在の状況 ===&lt;br /&gt;
&lt;br /&gt;
下から上がって来た流れと、上から下がってきた流れがぶつかり、しかもそれがうまく融合していない状態が続いていたという状況で、やっと今は、下からの流れを捨てつつ、上からの流れに追いついたといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
下からの流れがいちばん判りやすいのがMicrosoft社のセキュリティの問題です。&lt;br /&gt;
その主力製品であるWindowsは1つはWindows 95/98/Meという流れがあり、もう1つはWindows NT/2000/XPという流れがあります。&lt;br /&gt;
前者は、パーソナルコンピュータの流れ、後者は大型汎用機の流れです。ちなみにWindows NTを設計したのはDEC でVMSの開発をしていて、Microsoft社にヘッドハンティングされたデヴィッド・カトラーです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上から下がっていたオペレーティングシステムの体系に、下から上がってきたアプリケーション体系を合わせようとしても、なかなかうまくいきません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パーソナルコンピュータでは、使っているのは一人なわけですから、なんでもオールマイティーにアクセスしても一見問題はないように見えます。一方で大きなコンピュータは一人で使っていては、あまりにも高価なので、多人数で使えるなければなりませんし、そうなれば勝手に他人のファイルや、ましてや勝手にシステムの運用に関わる設定など変えてはいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
なんでもアクセスできてしまうパーソナルコンピュータのソフトウェアの方がシンプルかつ簡便な操作を提供できる...と考えても不思議ではありません。&lt;br /&gt;
しかし、便利であったはずの「なんでもアクセスできる」というのがセキュリティの面、特にコンピュータウィルスや脆弱性をついてのシステムへの侵入などクリティカルな問題へ結びつき、それが時代とともに表面化してきました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上からと下からの矛盾が現在のWindowsの根本的な問題となっていました。&lt;br /&gt;
Windows Vista以降では完全にユーザ権限を分離した管理体系による高いセキュリティを持つという能力を提供しています。&lt;br /&gt;
ですが、Windows XP まで動いていたアプリケーションやドライバー類が動かずデベロッパーやユーザが不満を漏らしていたという状況も一方ではありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように必要な安全性を達成するには、下から上へ上がってきたようなレガシーなソフトウェアを切り捨てなければ困難です。しかし、一方で膨大なソフトウェア資産があるわけです。この矛盾に終止符を打つのは大変長い時間がかかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : 1980年代のスーパーコンピュータやパソコンと呼ばれていたコンピュータの処理能力は、どの程度のものだったのだろうか。その能力の向上はどうだったのだろうか。&lt;br /&gt;
&lt;br /&gt;
== 何をさしてオペレーティングシステムと呼ぶのか ==&lt;br /&gt;
=== 広義と狭義の議論 ===&lt;br /&gt;
&lt;br /&gt;
[[File:Layer-of-System-2.png|thumb|right|400px|System Layer]]&lt;br /&gt;
&lt;br /&gt;
コンピュータ上で動いているソフトウェアのどの部分を指してオペレーティングシステムと呼ぶべきないのか、ということの定義を確認しましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここでは、一番最下層をハードウェアとして、次にあるのが[[カーネルの構造と機能|カーネルの層]]、その次が汎用に使われるシステムユーティリティの層、そして、特定目的のためにユーザが利用するアプリケーションの層というモデルを考えてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムと、システムユーティリティの両方を1つのまとまりとして、システムソフトウェアと呼びます。「システムを動かすのに最低限必要なソフトウェアセット」という広い意味で捉えたオペレーティングシステムであれば、このシステムソフトウェアがオペレーティングシステムと同意語であると言えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし「最小限必要な」という定義は、かなり曖昧な表現です。なぜならば、ここには「&#039;&#039;&#039;&#039;&#039;誰が、どのように使うか&#039;&#039;&#039;&#039;&#039;」ということが抜けているからです。&lt;br /&gt;
この部分を拡張していけば、たとえば「ワードブロセッシングを行いたい人が使うためのコンピュータ」という場合は「バンドルされているワードプロセッサのプログラムも含めてオペレーティングシステムである」という奇妙な結論が導かれてしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この「パッケージを購入した時にバンドルされているアプリケーション群が最小限のセットなので、これがオペレーティングシステムである」という誤解&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://ja.wikipedia.org/w/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;amp;oldid=29875236 日本語版wikipedia]ではウェブブラウザや時計などのアクセサリーも広義のオペレーティングシステムだということを書いていますが、そんなことをテストに書いて点数をくれる先生は極めて少数派でしょう。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は一般には多いようです。&lt;br /&gt;
もしこれが正しいとするならば、これではゲームのソリティアもオペレーティングシステムに含まれることになるので、やはり奇妙な結論と言えます。&lt;br /&gt;
このような表現での「最小パッケージ」とはGNU/Linuxのディストリビューションのデフォルトイントール環境にあたるもので、このオペレーティングシステムの定義を採用するとなると、世の中にはおびただしい数のオペレーティングシステムの種類&amp;lt;ref&amp;gt; オープンソース系オペレーティングシステムののディストリビューションを紹介する https://distrowatch.com  には実に様々なディストリビューションが紹介されています。&amp;lt;/ref&amp;gt;が存在することになります。このような定義を用いると、このような奇妙な結果が導き出されてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では逆に、ここは確実にオペレーティングシステムだろうと言える部分を考えてみます。まずカーネルは当然入ります。ユーザが使うということであれば、&lt;br /&gt;
シェルなども必要です。なぜならシェルがないとコマンドを入力できません。当然ユーザを認証するためのログインに関連するソフトウェアが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : カーネルとそれ以外のソフトウェアの切り分けは、実行されるプロセスの実行モードが、どの状態で動いているかで区別します。プロセスの実行モードが、カーネル・モード（UNIX以外のシステムによっては特権モード、スーパーバイザ・モード、あるいはマスタ・モードとも呼ばれる) で動作しているか、ユーザ・モード ( 非特権モード、プロブレム・モード、あるいはスレーブモードとも呼ばれる)で動作しているかどうかです。実行モードに関しては、実行とプロセスに関する話題の時に改めて説明します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どれくらいのものが最初に用意されるのか、Debian GNU/Linux 6.0を例にして調べてみました。&lt;br /&gt;
&lt;br /&gt;
  ディレクトリ名      コマンド数&lt;br /&gt;
  /bin              95&lt;br /&gt;
  /sbin             110 &lt;br /&gt;
  /usr/bin          452&lt;br /&gt;
  /usr/sbin         107&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 :  2011年時点で最新のDebian GNU/Linux 6.0 を参考にしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコマンド数も先に述べたようにすべてが必要であるとは限りません。最小限インストールの状態のDebian GNU/Linuxに入っているコマンド数を数えたに過ぎません。&lt;br /&gt;
しかしながら、いくつかのコマンドとそのコマンドで利用されるライブラリ群はオペレーティングシステムには必要になるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では、グラフィカルインタフェース(GUI)を提供するためのウィンドウシステムはオペレーティングシステムに入るのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一般的なUNIXシステムでは、GUIがなくても当然動きますし、サーバシステムではGUIなどは必須ではありません。もちろん先程のDebian GNU/Linux最小限セットの中にはX Window Systemは入っていません。逆にパーソナルコンピュータ用のオペレーティングシステムと呼び販売されているタイプのものではウィンドウシステムは切り離すことができないコンポーネントとなっています。&lt;br /&gt;
&lt;br /&gt;
=== 揺らぐ定義 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot-Oracle VM VirtualBox.png|thumb|right|450px|コンソールでTOPを実行]]&lt;br /&gt;
&lt;br /&gt;
右図は仮想マシンに&lt;br /&gt;
[https://www.virtualbox.org/ VirtualBox]&lt;br /&gt;
を使い、&lt;br /&gt;
[https://www.debian.org/ Debian GNU/Linux] 6.0&lt;br /&gt;
を最小限インストールし立ち上げてみた状態です。&lt;br /&gt;
もちろんGUIはインストールしていません。なぜならGUIが存在しなくともきちんとコンピュータは動くからです。&lt;br /&gt;
Debian GNU/Linux 6.0 はデスクトップやラップトップ、あるいはサーバに使われるディストリビューションで、組み込み用のものではありません。&lt;br /&gt;
top コマンドを使い、メモリや実行中のプロセスが、どのような状態になっているか観察してみました。&lt;br /&gt;
用意しているメモリは 128MB ですが、この状態で使われている記憶領域は約 26MB しか使っていません。&lt;br /&gt;
df を使ってディスクの利用状況を見てみると、最小のインストールでは約 645MB しか使っていません。&lt;br /&gt;
最小限のセットを考えた場合、このように小さいメモリでも動くことができます。&lt;br /&gt;
この程度の資源でも(英文であれば、ですが）十分にテキストを編集し、スペルをチェックし、フォーマットし、さらにプリンタに出力ができます。&lt;br /&gt;
十分に「パーソナルな」コンピュータだといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように使い方によって、あるいはユーザのニーズによって「最小限の」という言葉を使って表現している広義のオペレーティングシステムの意味は揺らぐのがわかるかと思います。&lt;br /&gt;
しかしながら揺らぐからといって無限に定義を拡大していくような問題でもありません。&lt;br /&gt;
そのあたりがグラデーションのようになっていて簡単には線引きないのが特徴だといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
==  コンピュータを仮想化させる == &lt;br /&gt;
[[File:Virtualization.png|thumb|right|450px|Virtualization]]&lt;br /&gt;
我々が、アプリケーションプログラムを使う時、プログラムがコンピュータを占有しているように見えます。ユーザが他にどれだけのプログラムが実行されているかなど気にすることなく使うことができます。&lt;br /&gt;
&lt;br /&gt;
実際は、オペレーティングシステムが、リソースを抽象化し、プログラムに使えるリソースを割り当てることをします。つまり、プログラムは、「仮想化されたコンピュータ」を割り当てられることになります。ユーザに使用許可（パーミッション）が与えられている限り利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
UNIXでは、どのような仮想化の例があるのでしょうか? 典型的な例をいくつかあげて見ましょう。&lt;br /&gt;
&lt;br /&gt;
* CPUのリソースは、プログラムに対し、プロセスという単位で割り当てられます。&lt;br /&gt;
&lt;br /&gt;
* プログラムの使う記憶空間のリソースは、仮想記憶によりコントロールされます。仮想記憶の機構により、主記憶だけではなく、補助記憶装置も使って、主記憶よりも大きい記憶空間を作ることが可能です。その中から、プログラムが必要な大きさの記憶空間リソースを割り当ています。&lt;br /&gt;
&lt;br /&gt;
* 永続的な記憶を保管しておくために、ファイルという抽象的なデータの保管メカニズムを使います。そのファイルを効率的かつ統一的に扱うために、ファイルシステムを作ります。ファイルシステムは、主記憶と補助記憶装置を使って、ファイルのリソースを提供します。&lt;br /&gt;
&lt;br /&gt;
* 入出力装置のリソースのために、デバイスファイルという入出力装置を抽象化した入出力リソースを提供しています。&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
:&#039;&#039;&#039;捕捉&#039;&#039;&#039; さらに&lt;br /&gt;
:[http://www.cl.cam.ac.uk/Research/SRG/netos/xen/ Xen]、[http://www.vmware.com/  VMware]、[https://www.virtualbox.org/ VirtualBox]のようにハードウェア側を抽象化し、1つのハードウェア上に複数のオペレーティングシステムを動かすバーチャルマシンのシステムもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 抽象化の例 ====&lt;br /&gt;
&lt;br /&gt;
UNIXの上で次のコマンドを実行すると端末にHelloと表示されます。これは文字列&amp;quot;Hello&amp;quot;を出力し、その出力先をファイル&lt;br /&gt;
/dev/tty&lt;br /&gt;
への入力するという働きをします。ファイル（デバイスファイルと呼びます）&lt;br /&gt;
/dev/tty&lt;br /&gt;
というのは、自端末を抽象化したものです。&lt;br /&gt;
いくつも端末のウインドウを開いて別々のシェルで行っても、ほかの端末には表示せず、自分の端末のみに出力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % echo &amp;quot;Hello&amp;quot; &amp;gt; /dev/tty&lt;br /&gt;
 Hello&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....E、は、オペレーティングシステムから利用可能なリソースを割り当てられ、その中で実行しています。しかし、アプリケーションA、B,....は、割り当てられたリソースのコントロールを意識しません。&lt;br /&gt;
例えば、プログラムがデータを補助記憶装置にファイルの形でデータを残そうとした時、プログラムが、補助記憶装置に使われているハードウェアを直接的にコントロールする必要はありません。つまり、1つのプログラムは、1つの仮想化されたコンピュータで動いているように見えるわけです。&lt;br /&gt;
&lt;br /&gt;
==== 不完全なリソース管理 ====&lt;br /&gt;
&lt;br /&gt;
もし、直接的にコントロールするはずのないリソースをユーザのアプリケーションプログラムがオペレーティングシステムを飛び越して直接的にコントロールできるようなことがあればどうなるのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
例えば、ユーザのアプリケーションプログラムにバグがあり、割り当てられたリソース以外のリソースを不用意に利用してしまうようなことを許すような不完全なリソース管理のオペレーティングシステムだとどうなるでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....は、オペレーティングシステムから割り当てられたリソースを使っているわけですから、オペレーティングシステムの知らない所で、割り当てられていないリソースに勝手なことをされては、一貫性が保てません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代のパソコンのオペレーティングシステム(と呼ばれていたもの)は、このような不完全なリソース管理の能力しか持っていませんでした。これらはオペレーティングシステムと呼ぶに値するのか非常に疑問で、本来はまだオペレーティングシステムまで発展していない前段階の機能であるハードウェアを監視するモニタと呼ばれるものに分類するのが適切であるように思えます。&lt;br /&gt;
&lt;br /&gt;
==== さらなる仮想化の例 ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== mmapとファイル =====&lt;br /&gt;
&lt;br /&gt;
例えば、UNIXのmmapと呼ぶ機能です。最近のUNIXは、[http://uc.h2np.net/index.php/%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86#mmap mmap]という機能を使ってプログラムは、ファイルを記憶空間に張り付ける (マップする) ことができます。主記憶、補助記憶装置のリソース区別が更に抽象化されプログラムの中で使える記憶空間としてのリソースとなります。もちろん通常のプログラムに割り当てられた記憶領域として、読み込み、書き込みすると、その内容がファイルに反映されます。さらに、ファイルという形で、複数のプロセスから、共有することができます。&lt;br /&gt;
&lt;br /&gt;
===== VFSからデバイスドライバまで =====&lt;br /&gt;
[[File:Filesystem-layer-1.png|thumb|right|400px|File System Layer]]&lt;br /&gt;
[[ファイルシステム]] をさらに抽象化するLinuxのファイルシステムを紹介しましょう。&lt;br /&gt;
ファイルを書き込む説明で「ハードディスクに書き込む」という表現をみたことはないでしょうか。&lt;br /&gt;
目の前にあるパソコン本体のみを考えるならば、このモノに書き出すというので説明は十分なのかも知れませんが、ファイルを書き込む・読み込むというのはもっと抽象的な動作をします。&lt;br /&gt;
&lt;br /&gt;
Linuxのファイルシステムは、上位にVFS (Virtual  File System)が存在し、その下に、FAT、ext4、JFS、XFS、NFS、その他のファイルシステムをもち、さらにその下にバッファキャッシュがあり、さらに下にデバイスドライバがあるといった、何重もの層を重ねる形になっています。&lt;br /&gt;
プログラムは、Linuxのファイルを扱っているだけで、その下がFATのファイルシステムやJFSのファイルシステムであるか、あるいはネットワーク経由でファイルシステムを使うことができるNFSなのかを知らなくても利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
下層には、補助記憶装置との入出力効率を改善するために、バッファキャッシュというクッションをおいてあります。&lt;br /&gt;
さらなる下層には、ハードディスクやフラッシュメモリ (例えばUSBメモリやSDカードなど)といった記憶するためのハードウェア、あるいはNFSのようにネットワークを経由して使うためのネットワークハードウェアをコントロールするためのデバイスドライバの層があります。&lt;br /&gt;
ファイルの情報が最終的にハードディスクに書かれるとしても、ファイルを書き込む動作を行った時点で、まだハードディスクにかかれているわけではありません。&lt;br /&gt;
このようなことにより、たぶん一度や二度は経験したことがあるかも知れませんが、突然、機材の電源を停止すると永続的な情報を保持するためのエリア(ハードディスクやUSBメモリなど)にかかれていなかったファイルの情報は消えてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % sync;sync;sync&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sync&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
syncを三回するのは &amp;quot;In the name of the Father, and of the Son, and of the Holy Spirit.(父と子と精霊の御名において)&amp;quot;と唱えて強制的にハードウェアリセットをするためだとむかし誰かに教わった。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
はバッファキャッシュなどにある情報を含めてすべてデバイスに同期させるコマンド。&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
このように重層的な構造にすることによって、抽象化を図り、かつどの層が変化しようとも、上位の層がその違いを吸収するような形になっています。またこのような枠組みにより柔軟に機能・モジュールを追加、変更することが出来る仕組みになっています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|1]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1765</id>
		<title>オペレーティングシステムとは何か</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1765"/>
		<updated>2025-07-23T04:07:31Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 上から下への流れ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== オペレーティングシステムとは何か == &lt;br /&gt;
&lt;br /&gt;
===  オペレーティングシステムの再確認 === &lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムとは何かを基本に戻って再確認してみましょう。&lt;br /&gt;
オペレーティングシステム( Operating System )を短く説明すれば、文字通りコンピュータを操作してゆく&lt;br /&gt;
(Operating/オペレーティング)&lt;br /&gt;
体系&lt;br /&gt;
(System/システム)&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの役目は次の３つの目標を達成するためにリソース&lt;br /&gt;
(Resources : 資源 )&lt;br /&gt;
と、&lt;br /&gt;
アプリケーション&lt;br /&gt;
( Applications : ユーザが使うソフトウェア )&lt;br /&gt;
の間に存在し両者を結び付けるための糊の役目をするソフトウェア群であるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* リソースを効率的に利用し、また管理をする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションが直接リソースを制御する必要をなくする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションにとってリソースをさらに抽象化する&lt;br /&gt;
&lt;br /&gt;
=== リソースとは === &lt;br /&gt;
&lt;br /&gt;
リソースとは、コンピュータ上にある、処理を行なう際に必要となる資源を意味する概念的なものです。&lt;br /&gt;
リソースとしてハードウェアリソースとソフトウェアリソースの2つはすぐに思い浮かぶでしょう。&lt;br /&gt;
さらに一歩踏み込んでオペレーティングシステムはコンピュータ・システムを利用するコストをより少なくするための道具と考えるならば、&lt;br /&gt;
利用者や運用者などを指してヒューマンリソースとしリソースの中に含める必要が出てきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまりハードウェアリソース、ソフトウェアリソース、ヒューマンリソースを有効に使うための役割がオペレーティングシステムには求められます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 捕捉 :  一口にコストといってもいろいろな場面でのコストがあります。また数値に現れるコストだけではなく、数値に現れにくく把握するのが難しいコストもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下に色々なリソースについて考えてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ハードウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ハードウェアリソースにはCPU、主記憶装置(メモリ）、補助記憶装置、入出力装置、ほかがあります。&lt;br /&gt;
&lt;br /&gt;
===== CPU =====&lt;br /&gt;
&lt;br /&gt;
CPU( Central Processing Unit : 中央演算処理装置 ) : 命令を実行し、演算を行なうユニット部分です。少し前までは、CPUの説明といえば、プロセッサチップを示せば終だったのですが、最近の高性能のプロセッサチップは、少々複雑になっています。現在のプロセッサチップは、キャッシュ記憶ユニットという高速に記憶を取り込むための、短期間だけ記憶を保持しているような記憶装置も内蔵しています。それ以外にも多くの機能を詰め込んでいます。そこまで分割していくと話が混乱しますので、ここでのCPU はプロセッサチップという具体的な製品ではなく、命令を実行し演算を行なうユニットという抽象的な役割部分だと理解してください。以降、他のCPU説明でも同じです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 主記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
主記憶装置 ( Main Memory Unit ) : いわゆるメモリのことです。&lt;br /&gt;
CPUと直接やりとりする記憶装置を指します。&lt;br /&gt;
演算のための値を記憶しておく、結果を記憶しておく、命令を記憶しておくなどといったために使われます。&lt;br /&gt;
以前は、単純にCPU ←→主メモリという構造で説明が十分だったのですが、現在での具体的な物理メモリの構成は、アクセスの効率を考え何段階かの動作速度や容量が異なるキャッシュメモリを用意しておき、CPUと記憶をやりとりしています。&lt;br /&gt;
わりきって一言でいうなら電気を切ったら消えてしまう一時的な記憶装置だといえます。&lt;br /&gt;
&lt;br /&gt;
===== 補助記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
補助記憶装置 ( Auxiliary Memory Unit ) : ハードディスクや磁気テープのような装置のことです。&lt;br /&gt;
現在ではコンパクトフラッシュメモリやUSBメモリなどもこのような区分けに入ってきます。&lt;br /&gt;
主記憶装置との違いは、CPUと直接記憶のやりとりを行なわないこと、記憶の容量が大きいこと、長期間記憶&lt;br /&gt;
(わり切って言えば電気を切っても消えない記憶)&lt;br /&gt;
を保持するユニットです。&lt;br /&gt;
&lt;br /&gt;
===== 入出力装置 =====&lt;br /&gt;
&lt;br /&gt;
入出力装置 ( Input/Output Unit ) : キーボード、マウス、ディスプレイといったものや、シリアルポートやパラレルポート、またあるいはネットワークボードといったものなどのがあげられます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:  ハードウェアリソースを構成&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 上 , ジョン・L. ヘネシー (著), デイビッド・A. パターソン (著), 成田 光彰 (翻訳), 2014/12/6, ISBN 4822298426&lt;br /&gt;
&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 下, デイビッド・A・パターソン (著), ジョン・L・ヘネシー (著), 成田光彰 (翻訳), 2014/12/6, ISBN 4822298434&lt;br /&gt;
&amp;lt;/ref&amp;gt;するものとしてこの他に、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
====  ソフトウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ソフトウェアは、そのコンピュータ上で動くソフトウェアで共有し利用するようなデータ、ライブラリ、プログラムを意味します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばオペレーティングシステムの心臓部である[[カーネルの構造と機能|カーネル部分]]、アプリケーションが使うライブラリ、あるいはシステムを運用する上で必要なコマンド群などがあげられます。データベースを考えるとアプリケーションとしてのデータベースプログラムとその中に格納されアプリケージョンに利用されるデータから成り立ちます。この両者があってソフトウェアリソースとして提供されるデータベースとして意味をなします。多種多様なソフトウェアリソースがどのような役割を担うのかの議論は後ほどしましょう。&lt;br /&gt;
&lt;br /&gt;
==== ヒューマンリソース ====&lt;br /&gt;
&lt;br /&gt;
人的なリソースです。コンピュータが非常に高価だった頃は、その利用のために人を雇うコストの方が小さいファクタだったため、あまり大きな関心は寄せられていませんでした。&lt;br /&gt;
昔の汎用機時代においては、人的コストよりもハードウェアのコストの方がはるかに高く、そのため人間が便利に使えるよりも、まずハードウェアを最も効率よく使うにはどうするべきかを優先していたのです。&lt;br /&gt;
高性能のコンピュータがコモディティ(日用品)化してしまっている現在では、人的なリソースの方が高価です。人的リソースの効率的利用できるようにすることもオペレーティングシステムには求められています。このように時代の流れでハードウェアのコストが下がるにつれ、人的コストの比率が相対的にあがってきます。このような状況では、今度は人的コストを如何に下げるかが今日の課題となっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039; : 人的なコストを低減するためにどのような工夫がなされているのだろうか。&lt;br /&gt;
&lt;br /&gt;
== オペレーティングシステムの潮流 ==&lt;br /&gt;
&lt;br /&gt;
時が立つにつれ、どんどんハードウェアが小型化し、また高性能になっていきます。&lt;br /&gt;
例えば、2010 年のデスクトップコンピュータ、いわゆるパソコンと呼ばれる機械の上位機種の計算スピードは、私がこの業界に入った 1980 年半ばのスーパーコンピュータ並、あるいはそれ以上の性能を持っています。この文章を読んでいるこの瞬間では、2010年のデスクトップパソコンなど性能的に時代遅れになっているでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1990 年当時から比較しても、エンジニアリングワークステーションと呼ばれていた数百万から一千万円くらいの価格だったコンピュータシステムよりも遥かに高速です。&amp;lt;ref&amp;gt;RASPBERRY PI 2 MODEL B http://www.raspberrypi.org/products/raspberry-pi-2-model-b/ &amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Iridis-pi: a low-cost, compact demonstration cluster https://www.southampton.ac.uk/~sjc/raspberrypi/raspberry_pi_iridis_lego_supercomputer_paper_cox_Jun2013.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
当然、そうなってくると、高性能なハードウェアを効率よく動かす、かつハードウェアの能力を引き出すために、かつて高価なコンピュータで使われたいたオペレーティングシステムのテクノロジーが必要になってきます。かくして、身近に高性能なオペレーティングシステム が使われるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 現在のオペレーティングシステムへ向かう2つの流れ ===&lt;br /&gt;
&lt;br /&gt;
現在のハードウェアとオペレーティングシステムの関係をハードウェアの歴史の変遷を踏まえて考えてみます。みなさんが使っているデスクトップのコンピュータに至る流れには2つの流れがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 下から上への流れ ====&lt;br /&gt;
&lt;br /&gt;
小さいものから、大きなものへ変化した様子を見てみましょう。&lt;br /&gt;
1971年に世界初のマイクロプロセッサIntel 4004 が出来てから、パーソナルコンピュータが作られ、どんどん性能が良くなってきた流れです。パーソナルコンピュータ、いわゆるパソコンは初めは玩具のようなものでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1975年に発売された世界初のパソコンMITS Altair 8080はIntel 8080 250Khz を搭載しメモリは256byteでした。キーボードもモニターも当然ながらハードディスクなどありません。プログラムはフロントパネルからスイッチを操作し、バイナリーのマシン語を入力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1976年ぐらいになると、Apple、Sol、Altairといった最も初期の頃のパソコンが作られてきます。この頃、Bill GatesとPaul AllenはAltair 8080 (メモリ4KByte版）用に大型汎用機上で動いていたBASIC言語を移植しMITSへライセンスします。翌、1977年には [[Steve Wozniak]] とSteve Jobs &amp;lt;ref&amp;gt; スティーブ・ジョブズ 1 (講談社+α文庫)  ISBN 4062816148 &amp;lt;/ref&amp;gt;がApple Corporationを設立し、また同じくしてBill Gates とPaul Allenは正式にMicrosoft companyを設立します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Apple や Sol や Altairのような初期のパソコンが作られます。スミソニアン博物館にある初期のパソコンたちの写真です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2551.JPG|thumb|220px|Homebrew computer club ]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2548.JPG|thumb|220px|Apple]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2549.JPG|thumb|220px|Sol]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2547.JPG|thumb|220px|Altair]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1984年にIBMがIBM PCを販売開始した時が、今日のパーソナルコンピュータ隆盛の時代の本格的な幕開けだったといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
初期の頃のパソコンにはオペレーティングシステムがありませんでした。次にCP/MやMS-DOSといった 低レベルな機能しか持たない原始的なオペレーティングシステムが現われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 機能が不十分なため厳密にはオペレーティングシステムとは呼べずモニターと呼ぶべきものだと筆者は考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:オペレーティングシステムの前段階ともいえるモニターとはなんだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはハードウェアの能力が極めて限られているので、大型汎用機のような機能を望むべくもなく、低レベルな機能しか持たざる得ないという限界があります。1990年代ともなると、高速なCPU、大容量のメモリー、大容量のハードディスクなどハードウェアの能力は格段に上がります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、一方で、そのハードウェア上で動かしているソフトウェアのシステム構造は古い頃から手直しを繰り返してアップグレードしてきたものです。さらにパーソナルな環境ではなく、ネットワークに繋がれ、さらにはインターネットに繋がれるまでになると、玩具の箱から個人のツールとして発展してきた単純なパーソナルコンピュータのモデルではいずれ限界が来てしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように下から上へ向かうトレンドが、まず1つあります。&lt;br /&gt;
&lt;br /&gt;
==== 上から下への流れ ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コンピュータが作られた時から、今日のパーソナルコンピュータが隆盛を究めるまでに至まで常にコンピュータのハードウェアは高価なものでした。&lt;br /&gt;
1960年当時初期までは、コンピュータはプログラムを走らせるために特別なセットアップが必要で、色々なプログラムを走らせることが困難でした。&lt;br /&gt;
高価なハードウェア上でもっと汎用的にプログラムを動かすために作られたシステムが1964年に作られたIBM S/360です。ここで始めて今日的なオペレーティングシステムが作られます。&lt;br /&gt;
汎用機という言葉は、この「汎用的にプログラムを動かすことができるシステム」という所から来ています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:NASAComputerRoom7090.NARA.jpg|left|thumb|300px| 1962年にNASAで使われていた IBM 7090 の写真(NASAサイトより)&amp;lt;ref&amp;gt;NASA の著作権ポリシー http://www.jsc.nasa.gov/policies.html#Guidelines&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
時代は流れ大型汎用機もダウンサイジングの流れには逆らえませんでした。&lt;br /&gt;
まず最初のダウンサイジングで成功したのはDEC社の科学技術計算用コンピュータPDPシリーズやVAXシリーズです。&lt;br /&gt;
これらはミニコンと呼ばれました。これは1970年代後半から80年代後期まで成功を納めます。&lt;br /&gt;
さらに時代は進み、今度はワークステーションの出現です。&lt;br /&gt;
90年代に入るとDEC社のVAXが、SUN MicrosystemsのSUN ワークステーションに置き換わることになります。&lt;br /&gt;
そのダウンサイジングに大きな役目を果たしたのがUNIXです。&lt;br /&gt;
UNIXはワークステーションからスーパコンピュータまであらゆるサイズのコンピュータ上で使えるようになっていました。&lt;br /&gt;
別の言い方をすれば、ワークステーションからスーパーコンピュータでも十分に満足できる今日的オペレーティングシステムの機能をUNIXは兼ね備えているというわけです。&lt;br /&gt;
しかし、まだ業務や科学技術計算で使うコンピュータと、パーソナルで使うコンピュータには価格的にも性能的にも大きな隔たりがありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代後半になるとIA-32 (&#039;&#039;Intel Architecture,32bit&#039;&#039;)のハードウェアに席捲されます。2000年以降は、ダウンサイジングの到着点です。もう個人で使うパーソナルコンピュータも、業務や科学技術計算で使うものも、ハードウェア的には価格的にも、使われている技術にも、処理能力にも線引きが出来できません。2005年では、64bit CPU、デュアルプロセッサ対応、デュアルコアCPUといった最先端のテクノロジーがコモディティ市場 (一般消費者向け市場) に売られている時代になりました。この傾向はこれから先も続きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 考えてみよう : ムーアの法則とは限界を示しているのか、いないのか。限界を示しているとしたらなぜなのか。あるいは、ないならばなぜなのか。尚、ムーアの法則の意味は、オリジナルの意味である集積度の向上と、派生的に多く使われている性能の向上のどちらの意味で取ってもよい。&lt;br /&gt;
&lt;br /&gt;
===  2007年現在の状況 ===&lt;br /&gt;
&lt;br /&gt;
下から上がって来た流れと、上から下がってきた流れがぶつかり、しかもそれがうまく融合していない状態が続いていたという状況で、やっと今は、下からの流れを捨てつつ、上からの流れに追いついたといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
下からの流れがいちばん判りやすいのがMicrosoft社のセキュリティの問題です。&lt;br /&gt;
その主力製品であるWindowsは1つはWindows 95/98/Meという流れがあり、もう1つはWindows NT/2000/XPという流れがあります。&lt;br /&gt;
前者は、パーソナルコンピュータの流れ、後者は大型汎用機の流れです。ちなみにWindows NTを設計したのはDEC でVMSの開発をしていて、Microsoft社にヘッドハンティングされたデビット・カトラーです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上から下がっていたオペレーティングシステムの体系に、下から上がってきたアプリケーション体系を合わせようとしても、なかなかうまくいきません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パーソナルコンピュータでは、使っているのは一人なわけですから、なんでもオールマイティーにアクセスしても一見問題はないように見えます。一方で大きなコンピュータは一人で使っていては、あまりにも高価なので、多人数で使えるなければなりませんし、そうなれば勝手に他人のファイルや、ましてや勝手にシステムの運用に関わる設定など変えてはいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
なんでもアクセスできてしまうパーソナルコンピュータのソフトウェアの方がシンプルかつ簡便な操作を提供できる...と考えても不思議ではありません。&lt;br /&gt;
しかし、便利であったはずの「なんでもアクセスできる」というのがセキュリティの面、特にコンピュータウィルスや脆弱性をついてのシステムへの侵入などクリティカルな問題へ結びつき、それが時代とともに表面化してきました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上からと下からの矛盾が現在のWindowsの根本的な問題となっていました。&lt;br /&gt;
Windows Vista以降では完全にユーザ権限を分離した管理体系による高いセキュリティを持つという能力を提供しています。&lt;br /&gt;
ですが、Windows XP まで動いていたアプリケーションやドライバー類が動かずデベロッパーやユーザが不満を漏らしていたという状況も一方ではありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように必要な安全性を達成するには、下から上へ上がってきたようなレガシーなソフトウェアを切り捨てなければ困難です。しかし、一方で膨大なソフトウェア資産があるわけです。この矛盾に終止符を打つのは大変長い時間がかかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : 1980年代のスーパーコンピュータやパソコンと呼ばれていたコンピュータの処理能力は、どの程度のものだったのだろうか。その能力の向上はどうだったのだろうか。&lt;br /&gt;
&lt;br /&gt;
== 何をさしてオペレーティングシステムと呼ぶのか ==&lt;br /&gt;
=== 広義と狭義の議論 ===&lt;br /&gt;
&lt;br /&gt;
[[File:Layer-of-System-2.png|thumb|right|400px|System Layer]]&lt;br /&gt;
&lt;br /&gt;
コンピュータ上で動いているソフトウェアのどの部分を指してオペレーティングシステムと呼ぶべきないのか、ということの定義を確認しましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここでは、一番最下層をハードウェアとして、次にあるのが[[カーネルの構造と機能|カーネルの層]]、その次が汎用に使われるシステムユーティリティの層、そして、特定目的のためにユーザが利用するアプリケーションの層というモデルを考えてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムと、システムユーティリティの両方を1つのまとまりとして、システムソフトウェアと呼びます。「システムを動かすのに最低限必要なソフトウェアセット」という広い意味で捉えたオペレーティングシステムであれば、このシステムソフトウェアがオペレーティングシステムと同意語であると言えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし「最小限必要な」という定義は、かなり曖昧な表現です。なぜならば、ここには「&#039;&#039;&#039;&#039;&#039;誰が、どのように使うか&#039;&#039;&#039;&#039;&#039;」ということが抜けているからです。&lt;br /&gt;
この部分を拡張していけば、たとえば「ワードブロセッシングを行いたい人が使うためのコンピュータ」という場合は「バンドルされているワードプロセッサのプログラムも含めてオペレーティングシステムである」という奇妙な結論が導かれてしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この「パッケージを購入した時にバンドルされているアプリケーション群が最小限のセットなので、これがオペレーティングシステムである」という誤解&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://ja.wikipedia.org/w/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;amp;oldid=29875236 日本語版wikipedia]ではウェブブラウザや時計などのアクセサリーも広義のオペレーティングシステムだということを書いていますが、そんなことをテストに書いて点数をくれる先生は極めて少数派でしょう。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は一般には多いようです。&lt;br /&gt;
もしこれが正しいとするならば、これではゲームのソリティアもオペレーティングシステムに含まれることになるので、やはり奇妙な結論と言えます。&lt;br /&gt;
このような表現での「最小パッケージ」とはGNU/Linuxのディストリビューションのデフォルトイントール環境にあたるもので、このオペレーティングシステムの定義を採用するとなると、世の中にはおびただしい数のオペレーティングシステムの種類&amp;lt;ref&amp;gt; オープンソース系オペレーティングシステムののディストリビューションを紹介する https://distrowatch.com  には実に様々なディストリビューションが紹介されています。&amp;lt;/ref&amp;gt;が存在することになります。このような定義を用いると、このような奇妙な結果が導き出されてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では逆に、ここは確実にオペレーティングシステムだろうと言える部分を考えてみます。まずカーネルは当然入ります。ユーザが使うということであれば、&lt;br /&gt;
シェルなども必要です。なぜならシェルがないとコマンドを入力できません。当然ユーザを認証するためのログインに関連するソフトウェアが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : カーネルとそれ以外のソフトウェアの切り分けは、実行されるプロセスの実行モードが、どの状態で動いているかで区別します。プロセスの実行モードが、カーネル・モード（UNIX以外のシステムによっては特権モード、スーパーバイザ・モード、あるいはマスタ・モードとも呼ばれる) で動作しているか、ユーザ・モード ( 非特権モード、プロブレム・モード、あるいはスレーブモードとも呼ばれる)で動作しているかどうかです。実行モードに関しては、実行とプロセスに関する話題の時に改めて説明します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どれくらいのものが最初に用意されるのか、Debian GNU/Linux 6.0を例にして調べてみました。&lt;br /&gt;
&lt;br /&gt;
  ディレクトリ名      コマンド数&lt;br /&gt;
  /bin              95&lt;br /&gt;
  /sbin             110 &lt;br /&gt;
  /usr/bin          452&lt;br /&gt;
  /usr/sbin         107&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 :  2011年時点で最新のDebian GNU/Linux 6.0 を参考にしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコマンド数も先に述べたようにすべてが必要であるとは限りません。最小限インストールの状態のDebian GNU/Linuxに入っているコマンド数を数えたに過ぎません。&lt;br /&gt;
しかしながら、いくつかのコマンドとそのコマンドで利用されるライブラリ群はオペレーティングシステムには必要になるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では、グラフィカルインタフェース(GUI)を提供するためのウィンドウシステムはオペレーティングシステムに入るのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一般的なUNIXシステムでは、GUIがなくても当然動きますし、サーバシステムではGUIなどは必須ではありません。もちろん先程のDebian GNU/Linux最小限セットの中にはX Window Systemは入っていません。逆にパーソナルコンピュータ用のオペレーティングシステムと呼び販売されているタイプのものではウィンドウシステムは切り離すことができないコンポーネントとなっています。&lt;br /&gt;
&lt;br /&gt;
=== 揺らぐ定義 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot-Oracle VM VirtualBox.png|thumb|right|450px|コンソールでTOPを実行]]&lt;br /&gt;
&lt;br /&gt;
右図は仮想マシンに&lt;br /&gt;
[https://www.virtualbox.org/ VirtualBox]&lt;br /&gt;
を使い、&lt;br /&gt;
[https://www.debian.org/ Debian GNU/Linux] 6.0&lt;br /&gt;
を最小限インストールし立ち上げてみた状態です。&lt;br /&gt;
もちろんGUIはインストールしていません。なぜならGUIが存在しなくともきちんとコンピュータは動くからです。&lt;br /&gt;
Debian GNU/Linux 6.0 はデスクトップやラップトップ、あるいはサーバに使われるディストリビューションで、組み込み用のものではありません。&lt;br /&gt;
top コマンドを使い、メモリや実行中のプロセスが、どのような状態になっているか観察してみました。&lt;br /&gt;
用意しているメモリは 128MB ですが、この状態で使われている記憶領域は約 26MB しか使っていません。&lt;br /&gt;
df を使ってディスクの利用状況を見てみると、最小のインストールでは約 645MB しか使っていません。&lt;br /&gt;
最小限のセットを考えた場合、このように小さいメモリでも動くことができます。&lt;br /&gt;
この程度の資源でも(英文であれば、ですが）十分にテキストを編集し、スペルをチェックし、フォーマットし、さらにプリンタに出力ができます。&lt;br /&gt;
十分に「パーソナルな」コンピュータだといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように使い方によって、あるいはユーザのニーズによって「最小限の」という言葉を使って表現している広義のオペレーティングシステムの意味は揺らぐのがわかるかと思います。&lt;br /&gt;
しかしながら揺らぐからといって無限に定義を拡大していくような問題でもありません。&lt;br /&gt;
そのあたりがグラデーションのようになっていて簡単には線引きないのが特徴だといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
==  コンピュータを仮想化させる == &lt;br /&gt;
[[File:Virtualization.png|thumb|right|450px|Virtualization]]&lt;br /&gt;
我々が、アプリケーションプログラムを使う時、プログラムがコンピュータを占有しているように見えます。ユーザが他にどれだけのプログラムが実行されているかなど気にすることなく使うことができます。&lt;br /&gt;
&lt;br /&gt;
実際は、オペレーティングシステムが、リソースを抽象化し、プログラムに使えるリソースを割り当てることをします。つまり、プログラムは、「仮想化されたコンピュータ」を割り当てられることになります。ユーザに使用許可（パーミッション）が与えられている限り利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
UNIXでは、どのような仮想化の例があるのでしょうか? 典型的な例をいくつかあげて見ましょう。&lt;br /&gt;
&lt;br /&gt;
* CPUのリソースは、プログラムに対し、プロセスという単位で割り当てられます。&lt;br /&gt;
&lt;br /&gt;
* プログラムの使う記憶空間のリソースは、仮想記憶によりコントロールされます。仮想記憶の機構により、主記憶だけではなく、補助記憶装置も使って、主記憶よりも大きい記憶空間を作ることが可能です。その中から、プログラムが必要な大きさの記憶空間リソースを割り当ています。&lt;br /&gt;
&lt;br /&gt;
* 永続的な記憶を保管しておくために、ファイルという抽象的なデータの保管メカニズムを使います。そのファイルを効率的かつ統一的に扱うために、ファイルシステムを作ります。ファイルシステムは、主記憶と補助記憶装置を使って、ファイルのリソースを提供します。&lt;br /&gt;
&lt;br /&gt;
* 入出力装置のリソースのために、デバイスファイルという入出力装置を抽象化した入出力リソースを提供しています。&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
:&#039;&#039;&#039;捕捉&#039;&#039;&#039; さらに&lt;br /&gt;
:[http://www.cl.cam.ac.uk/Research/SRG/netos/xen/ Xen]、[http://www.vmware.com/  VMware]、[https://www.virtualbox.org/ VirtualBox]のようにハードウェア側を抽象化し、1つのハードウェア上に複数のオペレーティングシステムを動かすバーチャルマシンのシステムもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 抽象化の例 ====&lt;br /&gt;
&lt;br /&gt;
UNIXの上で次のコマンドを実行すると端末にHelloと表示されます。これは文字列&amp;quot;Hello&amp;quot;を出力し、その出力先をファイル&lt;br /&gt;
/dev/tty&lt;br /&gt;
への入力するという働きをします。ファイル（デバイスファイルと呼びます）&lt;br /&gt;
/dev/tty&lt;br /&gt;
というのは、自端末を抽象化したものです。&lt;br /&gt;
いくつも端末のウインドウを開いて別々のシェルで行っても、ほかの端末には表示せず、自分の端末のみに出力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % echo &amp;quot;Hello&amp;quot; &amp;gt; /dev/tty&lt;br /&gt;
 Hello&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....E、は、オペレーティングシステムから利用可能なリソースを割り当てられ、その中で実行しています。しかし、アプリケーションA、B,....は、割り当てられたリソースのコントロールを意識しません。&lt;br /&gt;
例えば、プログラムがデータを補助記憶装置にファイルの形でデータを残そうとした時、プログラムが、補助記憶装置に使われているハードウェアを直接的にコントロールする必要はありません。つまり、1つのプログラムは、1つの仮想化されたコンピュータで動いているように見えるわけです。&lt;br /&gt;
&lt;br /&gt;
==== 不完全なリソース管理 ====&lt;br /&gt;
&lt;br /&gt;
もし、直接的にコントロールするはずのないリソースをユーザのアプリケーションプログラムがオペレーティングシステムを飛び越して直接的にコントロールできるようなことがあればどうなるのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
例えば、ユーザのアプリケーションプログラムにバグがあり、割り当てられたリソース以外のリソースを不用意に利用してしまうようなことを許すような不完全なリソース管理のオペレーティングシステムだとどうなるでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....は、オペレーティングシステムから割り当てられたリソースを使っているわけですから、オペレーティングシステムの知らない所で、割り当てられていないリソースに勝手なことをされては、一貫性が保てません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代のパソコンのオペレーティングシステム(と呼ばれていたもの)は、このような不完全なリソース管理の能力しか持っていませんでした。これらはオペレーティングシステムと呼ぶに値するのか非常に疑問で、本来はまだオペレーティングシステムまで発展していない前段階の機能であるハードウェアを監視するモニタと呼ばれるものに分類するのが適切であるように思えます。&lt;br /&gt;
&lt;br /&gt;
==== さらなる仮想化の例 ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== mmapとファイル =====&lt;br /&gt;
&lt;br /&gt;
例えば、UNIXのmmapと呼ぶ機能です。最近のUNIXは、[http://uc.h2np.net/index.php/%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86#mmap mmap]という機能を使ってプログラムは、ファイルを記憶空間に張り付ける (マップする) ことができます。主記憶、補助記憶装置のリソース区別が更に抽象化されプログラムの中で使える記憶空間としてのリソースとなります。もちろん通常のプログラムに割り当てられた記憶領域として、読み込み、書き込みすると、その内容がファイルに反映されます。さらに、ファイルという形で、複数のプロセスから、共有することができます。&lt;br /&gt;
&lt;br /&gt;
===== VFSからデバイスドライバまで =====&lt;br /&gt;
[[File:Filesystem-layer-1.png|thumb|right|400px|File System Layer]]&lt;br /&gt;
[[ファイルシステム]] をさらに抽象化するLinuxのファイルシステムを紹介しましょう。&lt;br /&gt;
ファイルを書き込む説明で「ハードディスクに書き込む」という表現をみたことはないでしょうか。&lt;br /&gt;
目の前にあるパソコン本体のみを考えるならば、このモノに書き出すというので説明は十分なのかも知れませんが、ファイルを書き込む・読み込むというのはもっと抽象的な動作をします。&lt;br /&gt;
&lt;br /&gt;
Linuxのファイルシステムは、上位にVFS (Virtual  File System)が存在し、その下に、FAT、ext4、JFS、XFS、NFS、その他のファイルシステムをもち、さらにその下にバッファキャッシュがあり、さらに下にデバイスドライバがあるといった、何重もの層を重ねる形になっています。&lt;br /&gt;
プログラムは、Linuxのファイルを扱っているだけで、その下がFATのファイルシステムやJFSのファイルシステムであるか、あるいはネットワーク経由でファイルシステムを使うことができるNFSなのかを知らなくても利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
下層には、補助記憶装置との入出力効率を改善するために、バッファキャッシュというクッションをおいてあります。&lt;br /&gt;
さらなる下層には、ハードディスクやフラッシュメモリ (例えばUSBメモリやSDカードなど)といった記憶するためのハードウェア、あるいはNFSのようにネットワークを経由して使うためのネットワークハードウェアをコントロールするためのデバイスドライバの層があります。&lt;br /&gt;
ファイルの情報が最終的にハードディスクに書かれるとしても、ファイルを書き込む動作を行った時点で、まだハードディスクにかかれているわけではありません。&lt;br /&gt;
このようなことにより、たぶん一度や二度は経験したことがあるかも知れませんが、突然、機材の電源を停止すると永続的な情報を保持するためのエリア(ハードディスクやUSBメモリなど)にかかれていなかったファイルの情報は消えてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % sync;sync;sync&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sync&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
syncを三回するのは &amp;quot;In the name of the Father, and of the Son, and of the Holy Spirit.(父と子と精霊の御名において)&amp;quot;と唱えて強制的にハードウェアリセットをするためだとむかし誰かに教わった。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
はバッファキャッシュなどにある情報を含めてすべてデバイスに同期させるコマンド。&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
このように重層的な構造にすることによって、抽象化を図り、かつどの層が変化しようとも、上位の層がその違いを吸収するような形になっています。またこのような枠組みにより柔軟に機能・モジュールを追加、変更することが出来る仕組みになっています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|1]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1764</id>
		<title>オペレーティングシステムとは何か</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1764"/>
		<updated>2025-07-23T04:05:54Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 上から下への流れ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== オペレーティングシステムとは何か == &lt;br /&gt;
&lt;br /&gt;
===  オペレーティングシステムの再確認 === &lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムとは何かを基本に戻って再確認してみましょう。&lt;br /&gt;
オペレーティングシステム( Operating System )を短く説明すれば、文字通りコンピュータを操作してゆく&lt;br /&gt;
(Operating/オペレーティング)&lt;br /&gt;
体系&lt;br /&gt;
(System/システム)&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの役目は次の３つの目標を達成するためにリソース&lt;br /&gt;
(Resources : 資源 )&lt;br /&gt;
と、&lt;br /&gt;
アプリケーション&lt;br /&gt;
( Applications : ユーザが使うソフトウェア )&lt;br /&gt;
の間に存在し両者を結び付けるための糊の役目をするソフトウェア群であるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* リソースを効率的に利用し、また管理をする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションが直接リソースを制御する必要をなくする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションにとってリソースをさらに抽象化する&lt;br /&gt;
&lt;br /&gt;
=== リソースとは === &lt;br /&gt;
&lt;br /&gt;
リソースとは、コンピュータ上にある、処理を行なう際に必要となる資源を意味する概念的なものです。&lt;br /&gt;
リソースとしてハードウェアリソースとソフトウェアリソースの2つはすぐに思い浮かぶでしょう。&lt;br /&gt;
さらに一歩踏み込んでオペレーティングシステムはコンピュータ・システムを利用するコストをより少なくするための道具と考えるならば、&lt;br /&gt;
利用者や運用者などを指してヒューマンリソースとしリソースの中に含める必要が出てきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまりハードウェアリソース、ソフトウェアリソース、ヒューマンリソースを有効に使うための役割がオペレーティングシステムには求められます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 捕捉 :  一口にコストといってもいろいろな場面でのコストがあります。また数値に現れるコストだけではなく、数値に現れにくく把握するのが難しいコストもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下に色々なリソースについて考えてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ハードウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ハードウェアリソースにはCPU、主記憶装置(メモリ）、補助記憶装置、入出力装置、ほかがあります。&lt;br /&gt;
&lt;br /&gt;
===== CPU =====&lt;br /&gt;
&lt;br /&gt;
CPU( Central Processing Unit : 中央演算処理装置 ) : 命令を実行し、演算を行なうユニット部分です。少し前までは、CPUの説明といえば、プロセッサチップを示せば終だったのですが、最近の高性能のプロセッサチップは、少々複雑になっています。現在のプロセッサチップは、キャッシュ記憶ユニットという高速に記憶を取り込むための、短期間だけ記憶を保持しているような記憶装置も内蔵しています。それ以外にも多くの機能を詰め込んでいます。そこまで分割していくと話が混乱しますので、ここでのCPU はプロセッサチップという具体的な製品ではなく、命令を実行し演算を行なうユニットという抽象的な役割部分だと理解してください。以降、他のCPU説明でも同じです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 主記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
主記憶装置 ( Main Memory Unit ) : いわゆるメモリのことです。&lt;br /&gt;
CPUと直接やりとりする記憶装置を指します。&lt;br /&gt;
演算のための値を記憶しておく、結果を記憶しておく、命令を記憶しておくなどといったために使われます。&lt;br /&gt;
以前は、単純にCPU ←→主メモリという構造で説明が十分だったのですが、現在での具体的な物理メモリの構成は、アクセスの効率を考え何段階かの動作速度や容量が異なるキャッシュメモリを用意しておき、CPUと記憶をやりとりしています。&lt;br /&gt;
わりきって一言でいうなら電気を切ったら消えてしまう一時的な記憶装置だといえます。&lt;br /&gt;
&lt;br /&gt;
===== 補助記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
補助記憶装置 ( Auxiliary Memory Unit ) : ハードディスクや磁気テープのような装置のことです。&lt;br /&gt;
現在ではコンパクトフラッシュメモリやUSBメモリなどもこのような区分けに入ってきます。&lt;br /&gt;
主記憶装置との違いは、CPUと直接記憶のやりとりを行なわないこと、記憶の容量が大きいこと、長期間記憶&lt;br /&gt;
(わり切って言えば電気を切っても消えない記憶)&lt;br /&gt;
を保持するユニットです。&lt;br /&gt;
&lt;br /&gt;
===== 入出力装置 =====&lt;br /&gt;
&lt;br /&gt;
入出力装置 ( Input/Output Unit ) : キーボード、マウス、ディスプレイといったものや、シリアルポートやパラレルポート、またあるいはネットワークボードといったものなどのがあげられます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:  ハードウェアリソースを構成&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 上 , ジョン・L. ヘネシー (著), デイビッド・A. パターソン (著), 成田 光彰 (翻訳), 2014/12/6, ISBN 4822298426&lt;br /&gt;
&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 下, デイビッド・A・パターソン (著), ジョン・L・ヘネシー (著), 成田光彰 (翻訳), 2014/12/6, ISBN 4822298434&lt;br /&gt;
&amp;lt;/ref&amp;gt;するものとしてこの他に、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
====  ソフトウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ソフトウェアは、そのコンピュータ上で動くソフトウェアで共有し利用するようなデータ、ライブラリ、プログラムを意味します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばオペレーティングシステムの心臓部である[[カーネルの構造と機能|カーネル部分]]、アプリケーションが使うライブラリ、あるいはシステムを運用する上で必要なコマンド群などがあげられます。データベースを考えるとアプリケーションとしてのデータベースプログラムとその中に格納されアプリケージョンに利用されるデータから成り立ちます。この両者があってソフトウェアリソースとして提供されるデータベースとして意味をなします。多種多様なソフトウェアリソースがどのような役割を担うのかの議論は後ほどしましょう。&lt;br /&gt;
&lt;br /&gt;
==== ヒューマンリソース ====&lt;br /&gt;
&lt;br /&gt;
人的なリソースです。コンピュータが非常に高価だった頃は、その利用のために人を雇うコストの方が小さいファクタだったため、あまり大きな関心は寄せられていませんでした。&lt;br /&gt;
昔の汎用機時代においては、人的コストよりもハードウェアのコストの方がはるかに高く、そのため人間が便利に使えるよりも、まずハードウェアを最も効率よく使うにはどうするべきかを優先していたのです。&lt;br /&gt;
高性能のコンピュータがコモディティ(日用品)化してしまっている現在では、人的なリソースの方が高価です。人的リソースの効率的利用できるようにすることもオペレーティングシステムには求められています。このように時代の流れでハードウェアのコストが下がるにつれ、人的コストの比率が相対的にあがってきます。このような状況では、今度は人的コストを如何に下げるかが今日の課題となっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039; : 人的なコストを低減するためにどのような工夫がなされているのだろうか。&lt;br /&gt;
&lt;br /&gt;
== オペレーティングシステムの潮流 ==&lt;br /&gt;
&lt;br /&gt;
時が立つにつれ、どんどんハードウェアが小型化し、また高性能になっていきます。&lt;br /&gt;
例えば、2010 年のデスクトップコンピュータ、いわゆるパソコンと呼ばれる機械の上位機種の計算スピードは、私がこの業界に入った 1980 年半ばのスーパーコンピュータ並、あるいはそれ以上の性能を持っています。この文章を読んでいるこの瞬間では、2010年のデスクトップパソコンなど性能的に時代遅れになっているでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1990 年当時から比較しても、エンジニアリングワークステーションと呼ばれていた数百万から一千万円くらいの価格だったコンピュータシステムよりも遥かに高速です。&amp;lt;ref&amp;gt;RASPBERRY PI 2 MODEL B http://www.raspberrypi.org/products/raspberry-pi-2-model-b/ &amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Iridis-pi: a low-cost, compact demonstration cluster https://www.southampton.ac.uk/~sjc/raspberrypi/raspberry_pi_iridis_lego_supercomputer_paper_cox_Jun2013.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
当然、そうなってくると、高性能なハードウェアを効率よく動かす、かつハードウェアの能力を引き出すために、かつて高価なコンピュータで使われたいたオペレーティングシステムのテクノロジーが必要になってきます。かくして、身近に高性能なオペレーティングシステム が使われるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 現在のオペレーティングシステムへ向かう2つの流れ ===&lt;br /&gt;
&lt;br /&gt;
現在のハードウェアとオペレーティングシステムの関係をハードウェアの歴史の変遷を踏まえて考えてみます。みなさんが使っているデスクトップのコンピュータに至る流れには2つの流れがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 下から上への流れ ====&lt;br /&gt;
&lt;br /&gt;
小さいものから、大きなものへ変化した様子を見てみましょう。&lt;br /&gt;
1971年に世界初のマイクロプロセッサIntel 4004 が出来てから、パーソナルコンピュータが作られ、どんどん性能が良くなってきた流れです。パーソナルコンピュータ、いわゆるパソコンは初めは玩具のようなものでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1975年に発売された世界初のパソコンMITS Altair 8080はIntel 8080 250Khz を搭載しメモリは256byteでした。キーボードもモニターも当然ながらハードディスクなどありません。プログラムはフロントパネルからスイッチを操作し、バイナリーのマシン語を入力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1976年ぐらいになると、Apple、Sol、Altairといった最も初期の頃のパソコンが作られてきます。この頃、Bill GatesとPaul AllenはAltair 8080 (メモリ4KByte版）用に大型汎用機上で動いていたBASIC言語を移植しMITSへライセンスします。翌、1977年には [[Steve Wozniak]] とSteve Jobs &amp;lt;ref&amp;gt; スティーブ・ジョブズ 1 (講談社+α文庫)  ISBN 4062816148 &amp;lt;/ref&amp;gt;がApple Corporationを設立し、また同じくしてBill Gates とPaul Allenは正式にMicrosoft companyを設立します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Apple や Sol や Altairのような初期のパソコンが作られます。スミソニアン博物館にある初期のパソコンたちの写真です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2551.JPG|thumb|220px|Homebrew computer club ]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2548.JPG|thumb|220px|Apple]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2549.JPG|thumb|220px|Sol]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2547.JPG|thumb|220px|Altair]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1984年にIBMがIBM PCを販売開始した時が、今日のパーソナルコンピュータ隆盛の時代の本格的な幕開けだったといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
初期の頃のパソコンにはオペレーティングシステムがありませんでした。次にCP/MやMS-DOSといった 低レベルな機能しか持たない原始的なオペレーティングシステムが現われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 機能が不十分なため厳密にはオペレーティングシステムとは呼べずモニターと呼ぶべきものだと筆者は考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:オペレーティングシステムの前段階ともいえるモニターとはなんだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはハードウェアの能力が極めて限られているので、大型汎用機のような機能を望むべくもなく、低レベルな機能しか持たざる得ないという限界があります。1990年代ともなると、高速なCPU、大容量のメモリー、大容量のハードディスクなどハードウェアの能力は格段に上がります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、一方で、そのハードウェア上で動かしているソフトウェアのシステム構造は古い頃から手直しを繰り返してアップグレードしてきたものです。さらにパーソナルな環境ではなく、ネットワークに繋がれ、さらにはインターネットに繋がれるまでになると、玩具の箱から個人のツールとして発展してきた単純なパーソナルコンピュータのモデルではいずれ限界が来てしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように下から上へ向かうトレンドが、まず1つあります。&lt;br /&gt;
&lt;br /&gt;
==== 上から下への流れ ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コンピュータが作られた時から、今日のパーソナルコンピュータが隆盛を究めるまでに至まで常にコンピュータのハードウェアは高価なものでした。&lt;br /&gt;
1960年当時初期までは、コンピュータはプログラムを走らせるために特別なセットアップが必要で、色々なプログラムを走らせることが困難でした。&lt;br /&gt;
高価なハードウェア上でもっと汎用的にプログラムを動かすために作られたシステムが1964年に作られたIBM S/360です。ここで始めて今日的なオペレーティングシステムが作られます。&lt;br /&gt;
汎用機という言葉は、この「汎用的にプログラムを動かすことができるシステム」という所から来ています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:NASAComputerRoom7090.NARA.jpg|left|thumb|300px| 1962年にNASAで使われていた IBM 7090 の写真(NASAサイトより)&amp;lt;ref&amp;gt;NASA の著作権ポリシー http://www.jsc.nasa.gov/policies.html#Guidelines&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
時代は流れ大型汎用機もダウンサイジングの波に流されます。&lt;br /&gt;
まず最初のダウンサイジングで成功したのはDEC社の科学技術計算用コンピュータPDPシリーズやVAXシリーズです。&lt;br /&gt;
これらはミニコンと呼ばれました。これは1970年代後半から80年代後期まで成功を納めます。&lt;br /&gt;
さらに時代は進み、今度はワークステーションの出現です。&lt;br /&gt;
90年代に入るとDEC社のVAXが、SUN MicrosystemsのSUN ワークステーションに置き換わることになります。&lt;br /&gt;
そのダウンサイジングに大きな役目を果たしたのがUNIXです。&lt;br /&gt;
UNIXはワークステーションからスーパコンピュータまであらゆるサイズのコンピュータ上で使えるようになっていました。&lt;br /&gt;
別の言い方をすれば、ワークステーションからスーパーコンピュータでも十分に満足できる今日的オペレーティングシステムの機能をUNIXは兼ね備えているというわけです。&lt;br /&gt;
しかし、まだ業務や科学技術計算で使うコンピュータと、パーソナルで使うコンピュータには価格的にも性能的にも大きな隔たりがありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代後半になるとIA-32 (&#039;&#039;Intel Architecture,32bit&#039;&#039;)のハードウェアに席捲されます。2000年以降は、ダウンサイジングの到着点です。もう個人で使うパーソナルコンピュータも、業務や科学技術計算で使うものも、ハードウェア的には価格的にも、使われている技術にも、処理能力にも線引きが出来できません。2005年では、64bit CPU、デュアルプロセッサ対応、デュアルコアCPUといった最先端のテクノロジーがコモディティ市場 (一般消費者向け市場) に売られている時代になりました。この傾向はこれから先も続きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 考えてみよう : ムーアの法則とは限界を示しているのか、いないのか。限界を示しているとしたらなぜなのか。あるいは、ないならばなぜなのか。尚、ムーアの法則の意味は、オリジナルの意味である集積度の向上と、派生的に多く使われている性能の向上のどちらの意味で取ってもよい。&lt;br /&gt;
&lt;br /&gt;
===  2007年現在の状況 ===&lt;br /&gt;
&lt;br /&gt;
下から上がって来た流れと、上から下がってきた流れがぶつかり、しかもそれがうまく融合していない状態が続いていたという状況で、やっと今は、下からの流れを捨てつつ、上からの流れに追いついたといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
下からの流れがいちばん判りやすいのがMicrosoft社のセキュリティの問題です。&lt;br /&gt;
その主力製品であるWindowsは1つはWindows 95/98/Meという流れがあり、もう1つはWindows NT/2000/XPという流れがあります。&lt;br /&gt;
前者は、パーソナルコンピュータの流れ、後者は大型汎用機の流れです。ちなみにWindows NTを設計したのはDEC でVMSの開発をしていて、Microsoft社にヘッドハンティングされたデビット・カトラーです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上から下がっていたオペレーティングシステムの体系に、下から上がってきたアプリケーション体系を合わせようとしても、なかなかうまくいきません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パーソナルコンピュータでは、使っているのは一人なわけですから、なんでもオールマイティーにアクセスしても一見問題はないように見えます。一方で大きなコンピュータは一人で使っていては、あまりにも高価なので、多人数で使えるなければなりませんし、そうなれば勝手に他人のファイルや、ましてや勝手にシステムの運用に関わる設定など変えてはいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
なんでもアクセスできてしまうパーソナルコンピュータのソフトウェアの方がシンプルかつ簡便な操作を提供できる...と考えても不思議ではありません。&lt;br /&gt;
しかし、便利であったはずの「なんでもアクセスできる」というのがセキュリティの面、特にコンピュータウィルスや脆弱性をついてのシステムへの侵入などクリティカルな問題へ結びつき、それが時代とともに表面化してきました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上からと下からの矛盾が現在のWindowsの根本的な問題となっていました。&lt;br /&gt;
Windows Vista以降では完全にユーザ権限を分離した管理体系による高いセキュリティを持つという能力を提供しています。&lt;br /&gt;
ですが、Windows XP まで動いていたアプリケーションやドライバー類が動かずデベロッパーやユーザが不満を漏らしていたという状況も一方ではありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように必要な安全性を達成するには、下から上へ上がってきたようなレガシーなソフトウェアを切り捨てなければ困難です。しかし、一方で膨大なソフトウェア資産があるわけです。この矛盾に終止符を打つのは大変長い時間がかかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : 1980年代のスーパーコンピュータやパソコンと呼ばれていたコンピュータの処理能力は、どの程度のものだったのだろうか。その能力の向上はどうだったのだろうか。&lt;br /&gt;
&lt;br /&gt;
== 何をさしてオペレーティングシステムと呼ぶのか ==&lt;br /&gt;
=== 広義と狭義の議論 ===&lt;br /&gt;
&lt;br /&gt;
[[File:Layer-of-System-2.png|thumb|right|400px|System Layer]]&lt;br /&gt;
&lt;br /&gt;
コンピュータ上で動いているソフトウェアのどの部分を指してオペレーティングシステムと呼ぶべきないのか、ということの定義を確認しましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここでは、一番最下層をハードウェアとして、次にあるのが[[カーネルの構造と機能|カーネルの層]]、その次が汎用に使われるシステムユーティリティの層、そして、特定目的のためにユーザが利用するアプリケーションの層というモデルを考えてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムと、システムユーティリティの両方を1つのまとまりとして、システムソフトウェアと呼びます。「システムを動かすのに最低限必要なソフトウェアセット」という広い意味で捉えたオペレーティングシステムであれば、このシステムソフトウェアがオペレーティングシステムと同意語であると言えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし「最小限必要な」という定義は、かなり曖昧な表現です。なぜならば、ここには「&#039;&#039;&#039;&#039;&#039;誰が、どのように使うか&#039;&#039;&#039;&#039;&#039;」ということが抜けているからです。&lt;br /&gt;
この部分を拡張していけば、たとえば「ワードブロセッシングを行いたい人が使うためのコンピュータ」という場合は「バンドルされているワードプロセッサのプログラムも含めてオペレーティングシステムである」という奇妙な結論が導かれてしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この「パッケージを購入した時にバンドルされているアプリケーション群が最小限のセットなので、これがオペレーティングシステムである」という誤解&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://ja.wikipedia.org/w/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;amp;oldid=29875236 日本語版wikipedia]ではウェブブラウザや時計などのアクセサリーも広義のオペレーティングシステムだということを書いていますが、そんなことをテストに書いて点数をくれる先生は極めて少数派でしょう。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は一般には多いようです。&lt;br /&gt;
もしこれが正しいとするならば、これではゲームのソリティアもオペレーティングシステムに含まれることになるので、やはり奇妙な結論と言えます。&lt;br /&gt;
このような表現での「最小パッケージ」とはGNU/Linuxのディストリビューションのデフォルトイントール環境にあたるもので、このオペレーティングシステムの定義を採用するとなると、世の中にはおびただしい数のオペレーティングシステムの種類&amp;lt;ref&amp;gt; オープンソース系オペレーティングシステムののディストリビューションを紹介する https://distrowatch.com  には実に様々なディストリビューションが紹介されています。&amp;lt;/ref&amp;gt;が存在することになります。このような定義を用いると、このような奇妙な結果が導き出されてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では逆に、ここは確実にオペレーティングシステムだろうと言える部分を考えてみます。まずカーネルは当然入ります。ユーザが使うということであれば、&lt;br /&gt;
シェルなども必要です。なぜならシェルがないとコマンドを入力できません。当然ユーザを認証するためのログインに関連するソフトウェアが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : カーネルとそれ以外のソフトウェアの切り分けは、実行されるプロセスの実行モードが、どの状態で動いているかで区別します。プロセスの実行モードが、カーネル・モード（UNIX以外のシステムによっては特権モード、スーパーバイザ・モード、あるいはマスタ・モードとも呼ばれる) で動作しているか、ユーザ・モード ( 非特権モード、プロブレム・モード、あるいはスレーブモードとも呼ばれる)で動作しているかどうかです。実行モードに関しては、実行とプロセスに関する話題の時に改めて説明します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どれくらいのものが最初に用意されるのか、Debian GNU/Linux 6.0を例にして調べてみました。&lt;br /&gt;
&lt;br /&gt;
  ディレクトリ名      コマンド数&lt;br /&gt;
  /bin              95&lt;br /&gt;
  /sbin             110 &lt;br /&gt;
  /usr/bin          452&lt;br /&gt;
  /usr/sbin         107&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 :  2011年時点で最新のDebian GNU/Linux 6.0 を参考にしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコマンド数も先に述べたようにすべてが必要であるとは限りません。最小限インストールの状態のDebian GNU/Linuxに入っているコマンド数を数えたに過ぎません。&lt;br /&gt;
しかしながら、いくつかのコマンドとそのコマンドで利用されるライブラリ群はオペレーティングシステムには必要になるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では、グラフィカルインタフェース(GUI)を提供するためのウィンドウシステムはオペレーティングシステムに入るのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一般的なUNIXシステムでは、GUIがなくても当然動きますし、サーバシステムではGUIなどは必須ではありません。もちろん先程のDebian GNU/Linux最小限セットの中にはX Window Systemは入っていません。逆にパーソナルコンピュータ用のオペレーティングシステムと呼び販売されているタイプのものではウィンドウシステムは切り離すことができないコンポーネントとなっています。&lt;br /&gt;
&lt;br /&gt;
=== 揺らぐ定義 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot-Oracle VM VirtualBox.png|thumb|right|450px|コンソールでTOPを実行]]&lt;br /&gt;
&lt;br /&gt;
右図は仮想マシンに&lt;br /&gt;
[https://www.virtualbox.org/ VirtualBox]&lt;br /&gt;
を使い、&lt;br /&gt;
[https://www.debian.org/ Debian GNU/Linux] 6.0&lt;br /&gt;
を最小限インストールし立ち上げてみた状態です。&lt;br /&gt;
もちろんGUIはインストールしていません。なぜならGUIが存在しなくともきちんとコンピュータは動くからです。&lt;br /&gt;
Debian GNU/Linux 6.0 はデスクトップやラップトップ、あるいはサーバに使われるディストリビューションで、組み込み用のものではありません。&lt;br /&gt;
top コマンドを使い、メモリや実行中のプロセスが、どのような状態になっているか観察してみました。&lt;br /&gt;
用意しているメモリは 128MB ですが、この状態で使われている記憶領域は約 26MB しか使っていません。&lt;br /&gt;
df を使ってディスクの利用状況を見てみると、最小のインストールでは約 645MB しか使っていません。&lt;br /&gt;
最小限のセットを考えた場合、このように小さいメモリでも動くことができます。&lt;br /&gt;
この程度の資源でも(英文であれば、ですが）十分にテキストを編集し、スペルをチェックし、フォーマットし、さらにプリンタに出力ができます。&lt;br /&gt;
十分に「パーソナルな」コンピュータだといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように使い方によって、あるいはユーザのニーズによって「最小限の」という言葉を使って表現している広義のオペレーティングシステムの意味は揺らぐのがわかるかと思います。&lt;br /&gt;
しかしながら揺らぐからといって無限に定義を拡大していくような問題でもありません。&lt;br /&gt;
そのあたりがグラデーションのようになっていて簡単には線引きないのが特徴だといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
==  コンピュータを仮想化させる == &lt;br /&gt;
[[File:Virtualization.png|thumb|right|450px|Virtualization]]&lt;br /&gt;
我々が、アプリケーションプログラムを使う時、プログラムがコンピュータを占有しているように見えます。ユーザが他にどれだけのプログラムが実行されているかなど気にすることなく使うことができます。&lt;br /&gt;
&lt;br /&gt;
実際は、オペレーティングシステムが、リソースを抽象化し、プログラムに使えるリソースを割り当てることをします。つまり、プログラムは、「仮想化されたコンピュータ」を割り当てられることになります。ユーザに使用許可（パーミッション）が与えられている限り利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
UNIXでは、どのような仮想化の例があるのでしょうか? 典型的な例をいくつかあげて見ましょう。&lt;br /&gt;
&lt;br /&gt;
* CPUのリソースは、プログラムに対し、プロセスという単位で割り当てられます。&lt;br /&gt;
&lt;br /&gt;
* プログラムの使う記憶空間のリソースは、仮想記憶によりコントロールされます。仮想記憶の機構により、主記憶だけではなく、補助記憶装置も使って、主記憶よりも大きい記憶空間を作ることが可能です。その中から、プログラムが必要な大きさの記憶空間リソースを割り当ています。&lt;br /&gt;
&lt;br /&gt;
* 永続的な記憶を保管しておくために、ファイルという抽象的なデータの保管メカニズムを使います。そのファイルを効率的かつ統一的に扱うために、ファイルシステムを作ります。ファイルシステムは、主記憶と補助記憶装置を使って、ファイルのリソースを提供します。&lt;br /&gt;
&lt;br /&gt;
* 入出力装置のリソースのために、デバイスファイルという入出力装置を抽象化した入出力リソースを提供しています。&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
:&#039;&#039;&#039;捕捉&#039;&#039;&#039; さらに&lt;br /&gt;
:[http://www.cl.cam.ac.uk/Research/SRG/netos/xen/ Xen]、[http://www.vmware.com/  VMware]、[https://www.virtualbox.org/ VirtualBox]のようにハードウェア側を抽象化し、1つのハードウェア上に複数のオペレーティングシステムを動かすバーチャルマシンのシステムもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 抽象化の例 ====&lt;br /&gt;
&lt;br /&gt;
UNIXの上で次のコマンドを実行すると端末にHelloと表示されます。これは文字列&amp;quot;Hello&amp;quot;を出力し、その出力先をファイル&lt;br /&gt;
/dev/tty&lt;br /&gt;
への入力するという働きをします。ファイル（デバイスファイルと呼びます）&lt;br /&gt;
/dev/tty&lt;br /&gt;
というのは、自端末を抽象化したものです。&lt;br /&gt;
いくつも端末のウインドウを開いて別々のシェルで行っても、ほかの端末には表示せず、自分の端末のみに出力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % echo &amp;quot;Hello&amp;quot; &amp;gt; /dev/tty&lt;br /&gt;
 Hello&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....E、は、オペレーティングシステムから利用可能なリソースを割り当てられ、その中で実行しています。しかし、アプリケーションA、B,....は、割り当てられたリソースのコントロールを意識しません。&lt;br /&gt;
例えば、プログラムがデータを補助記憶装置にファイルの形でデータを残そうとした時、プログラムが、補助記憶装置に使われているハードウェアを直接的にコントロールする必要はありません。つまり、1つのプログラムは、1つの仮想化されたコンピュータで動いているように見えるわけです。&lt;br /&gt;
&lt;br /&gt;
==== 不完全なリソース管理 ====&lt;br /&gt;
&lt;br /&gt;
もし、直接的にコントロールするはずのないリソースをユーザのアプリケーションプログラムがオペレーティングシステムを飛び越して直接的にコントロールできるようなことがあればどうなるのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
例えば、ユーザのアプリケーションプログラムにバグがあり、割り当てられたリソース以外のリソースを不用意に利用してしまうようなことを許すような不完全なリソース管理のオペレーティングシステムだとどうなるでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....は、オペレーティングシステムから割り当てられたリソースを使っているわけですから、オペレーティングシステムの知らない所で、割り当てられていないリソースに勝手なことをされては、一貫性が保てません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代のパソコンのオペレーティングシステム(と呼ばれていたもの)は、このような不完全なリソース管理の能力しか持っていませんでした。これらはオペレーティングシステムと呼ぶに値するのか非常に疑問で、本来はまだオペレーティングシステムまで発展していない前段階の機能であるハードウェアを監視するモニタと呼ばれるものに分類するのが適切であるように思えます。&lt;br /&gt;
&lt;br /&gt;
==== さらなる仮想化の例 ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== mmapとファイル =====&lt;br /&gt;
&lt;br /&gt;
例えば、UNIXのmmapと呼ぶ機能です。最近のUNIXは、[http://uc.h2np.net/index.php/%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86#mmap mmap]という機能を使ってプログラムは、ファイルを記憶空間に張り付ける (マップする) ことができます。主記憶、補助記憶装置のリソース区別が更に抽象化されプログラムの中で使える記憶空間としてのリソースとなります。もちろん通常のプログラムに割り当てられた記憶領域として、読み込み、書き込みすると、その内容がファイルに反映されます。さらに、ファイルという形で、複数のプロセスから、共有することができます。&lt;br /&gt;
&lt;br /&gt;
===== VFSからデバイスドライバまで =====&lt;br /&gt;
[[File:Filesystem-layer-1.png|thumb|right|400px|File System Layer]]&lt;br /&gt;
[[ファイルシステム]] をさらに抽象化するLinuxのファイルシステムを紹介しましょう。&lt;br /&gt;
ファイルを書き込む説明で「ハードディスクに書き込む」という表現をみたことはないでしょうか。&lt;br /&gt;
目の前にあるパソコン本体のみを考えるならば、このモノに書き出すというので説明は十分なのかも知れませんが、ファイルを書き込む・読み込むというのはもっと抽象的な動作をします。&lt;br /&gt;
&lt;br /&gt;
Linuxのファイルシステムは、上位にVFS (Virtual  File System)が存在し、その下に、FAT、ext4、JFS、XFS、NFS、その他のファイルシステムをもち、さらにその下にバッファキャッシュがあり、さらに下にデバイスドライバがあるといった、何重もの層を重ねる形になっています。&lt;br /&gt;
プログラムは、Linuxのファイルを扱っているだけで、その下がFATのファイルシステムやJFSのファイルシステムであるか、あるいはネットワーク経由でファイルシステムを使うことができるNFSなのかを知らなくても利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
下層には、補助記憶装置との入出力効率を改善するために、バッファキャッシュというクッションをおいてあります。&lt;br /&gt;
さらなる下層には、ハードディスクやフラッシュメモリ (例えばUSBメモリやSDカードなど)といった記憶するためのハードウェア、あるいはNFSのようにネットワークを経由して使うためのネットワークハードウェアをコントロールするためのデバイスドライバの層があります。&lt;br /&gt;
ファイルの情報が最終的にハードディスクに書かれるとしても、ファイルを書き込む動作を行った時点で、まだハードディスクにかかれているわけではありません。&lt;br /&gt;
このようなことにより、たぶん一度や二度は経験したことがあるかも知れませんが、突然、機材の電源を停止すると永続的な情報を保持するためのエリア(ハードディスクやUSBメモリなど)にかかれていなかったファイルの情報は消えてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % sync;sync;sync&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sync&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
syncを三回するのは &amp;quot;In the name of the Father, and of the Son, and of the Holy Spirit.(父と子と精霊の御名において)&amp;quot;と唱えて強制的にハードウェアリセットをするためだとむかし誰かに教わった。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
はバッファキャッシュなどにある情報を含めてすべてデバイスに同期させるコマンド。&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
このように重層的な構造にすることによって、抽象化を図り、かつどの層が変化しようとも、上位の層がその違いを吸収するような形になっています。またこのような枠組みにより柔軟に機能・モジュールを追加、変更することが出来る仕組みになっています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|1]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1763</id>
		<title>オペレーティングシステムとは何か</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1763"/>
		<updated>2025-07-23T04:04:50Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 下から上への流れ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== オペレーティングシステムとは何か == &lt;br /&gt;
&lt;br /&gt;
===  オペレーティングシステムの再確認 === &lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムとは何かを基本に戻って再確認してみましょう。&lt;br /&gt;
オペレーティングシステム( Operating System )を短く説明すれば、文字通りコンピュータを操作してゆく&lt;br /&gt;
(Operating/オペレーティング)&lt;br /&gt;
体系&lt;br /&gt;
(System/システム)&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの役目は次の３つの目標を達成するためにリソース&lt;br /&gt;
(Resources : 資源 )&lt;br /&gt;
と、&lt;br /&gt;
アプリケーション&lt;br /&gt;
( Applications : ユーザが使うソフトウェア )&lt;br /&gt;
の間に存在し両者を結び付けるための糊の役目をするソフトウェア群であるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* リソースを効率的に利用し、また管理をする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションが直接リソースを制御する必要をなくする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションにとってリソースをさらに抽象化する&lt;br /&gt;
&lt;br /&gt;
=== リソースとは === &lt;br /&gt;
&lt;br /&gt;
リソースとは、コンピュータ上にある、処理を行なう際に必要となる資源を意味する概念的なものです。&lt;br /&gt;
リソースとしてハードウェアリソースとソフトウェアリソースの2つはすぐに思い浮かぶでしょう。&lt;br /&gt;
さらに一歩踏み込んでオペレーティングシステムはコンピュータ・システムを利用するコストをより少なくするための道具と考えるならば、&lt;br /&gt;
利用者や運用者などを指してヒューマンリソースとしリソースの中に含める必要が出てきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまりハードウェアリソース、ソフトウェアリソース、ヒューマンリソースを有効に使うための役割がオペレーティングシステムには求められます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 捕捉 :  一口にコストといってもいろいろな場面でのコストがあります。また数値に現れるコストだけではなく、数値に現れにくく把握するのが難しいコストもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下に色々なリソースについて考えてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ハードウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ハードウェアリソースにはCPU、主記憶装置(メモリ）、補助記憶装置、入出力装置、ほかがあります。&lt;br /&gt;
&lt;br /&gt;
===== CPU =====&lt;br /&gt;
&lt;br /&gt;
CPU( Central Processing Unit : 中央演算処理装置 ) : 命令を実行し、演算を行なうユニット部分です。少し前までは、CPUの説明といえば、プロセッサチップを示せば終だったのですが、最近の高性能のプロセッサチップは、少々複雑になっています。現在のプロセッサチップは、キャッシュ記憶ユニットという高速に記憶を取り込むための、短期間だけ記憶を保持しているような記憶装置も内蔵しています。それ以外にも多くの機能を詰め込んでいます。そこまで分割していくと話が混乱しますので、ここでのCPU はプロセッサチップという具体的な製品ではなく、命令を実行し演算を行なうユニットという抽象的な役割部分だと理解してください。以降、他のCPU説明でも同じです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 主記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
主記憶装置 ( Main Memory Unit ) : いわゆるメモリのことです。&lt;br /&gt;
CPUと直接やりとりする記憶装置を指します。&lt;br /&gt;
演算のための値を記憶しておく、結果を記憶しておく、命令を記憶しておくなどといったために使われます。&lt;br /&gt;
以前は、単純にCPU ←→主メモリという構造で説明が十分だったのですが、現在での具体的な物理メモリの構成は、アクセスの効率を考え何段階かの動作速度や容量が異なるキャッシュメモリを用意しておき、CPUと記憶をやりとりしています。&lt;br /&gt;
わりきって一言でいうなら電気を切ったら消えてしまう一時的な記憶装置だといえます。&lt;br /&gt;
&lt;br /&gt;
===== 補助記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
補助記憶装置 ( Auxiliary Memory Unit ) : ハードディスクや磁気テープのような装置のことです。&lt;br /&gt;
現在ではコンパクトフラッシュメモリやUSBメモリなどもこのような区分けに入ってきます。&lt;br /&gt;
主記憶装置との違いは、CPUと直接記憶のやりとりを行なわないこと、記憶の容量が大きいこと、長期間記憶&lt;br /&gt;
(わり切って言えば電気を切っても消えない記憶)&lt;br /&gt;
を保持するユニットです。&lt;br /&gt;
&lt;br /&gt;
===== 入出力装置 =====&lt;br /&gt;
&lt;br /&gt;
入出力装置 ( Input/Output Unit ) : キーボード、マウス、ディスプレイといったものや、シリアルポートやパラレルポート、またあるいはネットワークボードといったものなどのがあげられます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:  ハードウェアリソースを構成&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 上 , ジョン・L. ヘネシー (著), デイビッド・A. パターソン (著), 成田 光彰 (翻訳), 2014/12/6, ISBN 4822298426&lt;br /&gt;
&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 下, デイビッド・A・パターソン (著), ジョン・L・ヘネシー (著), 成田光彰 (翻訳), 2014/12/6, ISBN 4822298434&lt;br /&gt;
&amp;lt;/ref&amp;gt;するものとしてこの他に、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
====  ソフトウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ソフトウェアは、そのコンピュータ上で動くソフトウェアで共有し利用するようなデータ、ライブラリ、プログラムを意味します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばオペレーティングシステムの心臓部である[[カーネルの構造と機能|カーネル部分]]、アプリケーションが使うライブラリ、あるいはシステムを運用する上で必要なコマンド群などがあげられます。データベースを考えるとアプリケーションとしてのデータベースプログラムとその中に格納されアプリケージョンに利用されるデータから成り立ちます。この両者があってソフトウェアリソースとして提供されるデータベースとして意味をなします。多種多様なソフトウェアリソースがどのような役割を担うのかの議論は後ほどしましょう。&lt;br /&gt;
&lt;br /&gt;
==== ヒューマンリソース ====&lt;br /&gt;
&lt;br /&gt;
人的なリソースです。コンピュータが非常に高価だった頃は、その利用のために人を雇うコストの方が小さいファクタだったため、あまり大きな関心は寄せられていませんでした。&lt;br /&gt;
昔の汎用機時代においては、人的コストよりもハードウェアのコストの方がはるかに高く、そのため人間が便利に使えるよりも、まずハードウェアを最も効率よく使うにはどうするべきかを優先していたのです。&lt;br /&gt;
高性能のコンピュータがコモディティ(日用品)化してしまっている現在では、人的なリソースの方が高価です。人的リソースの効率的利用できるようにすることもオペレーティングシステムには求められています。このように時代の流れでハードウェアのコストが下がるにつれ、人的コストの比率が相対的にあがってきます。このような状況では、今度は人的コストを如何に下げるかが今日の課題となっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039; : 人的なコストを低減するためにどのような工夫がなされているのだろうか。&lt;br /&gt;
&lt;br /&gt;
== オペレーティングシステムの潮流 ==&lt;br /&gt;
&lt;br /&gt;
時が立つにつれ、どんどんハードウェアが小型化し、また高性能になっていきます。&lt;br /&gt;
例えば、2010 年のデスクトップコンピュータ、いわゆるパソコンと呼ばれる機械の上位機種の計算スピードは、私がこの業界に入った 1980 年半ばのスーパーコンピュータ並、あるいはそれ以上の性能を持っています。この文章を読んでいるこの瞬間では、2010年のデスクトップパソコンなど性能的に時代遅れになっているでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1990 年当時から比較しても、エンジニアリングワークステーションと呼ばれていた数百万から一千万円くらいの価格だったコンピュータシステムよりも遥かに高速です。&amp;lt;ref&amp;gt;RASPBERRY PI 2 MODEL B http://www.raspberrypi.org/products/raspberry-pi-2-model-b/ &amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Iridis-pi: a low-cost, compact demonstration cluster https://www.southampton.ac.uk/~sjc/raspberrypi/raspberry_pi_iridis_lego_supercomputer_paper_cox_Jun2013.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
当然、そうなってくると、高性能なハードウェアを効率よく動かす、かつハードウェアの能力を引き出すために、かつて高価なコンピュータで使われたいたオペレーティングシステムのテクノロジーが必要になってきます。かくして、身近に高性能なオペレーティングシステム が使われるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 現在のオペレーティングシステムへ向かう2つの流れ ===&lt;br /&gt;
&lt;br /&gt;
現在のハードウェアとオペレーティングシステムの関係をハードウェアの歴史の変遷を踏まえて考えてみます。みなさんが使っているデスクトップのコンピュータに至る流れには2つの流れがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 下から上への流れ ====&lt;br /&gt;
&lt;br /&gt;
小さいものから、大きなものへ変化した様子を見てみましょう。&lt;br /&gt;
1971年に世界初のマイクロプロセッサIntel 4004 が出来てから、パーソナルコンピュータが作られ、どんどん性能が良くなってきた流れです。パーソナルコンピュータ、いわゆるパソコンは初めは玩具のようなものでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1975年に発売された世界初のパソコンMITS Altair 8080はIntel 8080 250Khz を搭載しメモリは256byteでした。キーボードもモニターも当然ながらハードディスクなどありません。プログラムはフロントパネルからスイッチを操作し、バイナリーのマシン語を入力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1976年ぐらいになると、Apple、Sol、Altairといった最も初期の頃のパソコンが作られてきます。この頃、Bill GatesとPaul AllenはAltair 8080 (メモリ4KByte版）用に大型汎用機上で動いていたBASIC言語を移植しMITSへライセンスします。翌、1977年には [[Steve Wozniak]] とSteve Jobs &amp;lt;ref&amp;gt; スティーブ・ジョブズ 1 (講談社+α文庫)  ISBN 4062816148 &amp;lt;/ref&amp;gt;がApple Corporationを設立し、また同じくしてBill Gates とPaul Allenは正式にMicrosoft companyを設立します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Apple や Sol や Altairのような初期のパソコンが作られます。スミソニアン博物館にある初期のパソコンたちの写真です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2551.JPG|thumb|220px|Homebrew computer club ]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2548.JPG|thumb|220px|Apple]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2549.JPG|thumb|220px|Sol]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2547.JPG|thumb|220px|Altair]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1984年にIBMがIBM PCを販売開始した時が、今日のパーソナルコンピュータ隆盛の時代の本格的な幕開けだったといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
初期の頃のパソコンにはオペレーティングシステムがありませんでした。次にCP/MやMS-DOSといった 低レベルな機能しか持たない原始的なオペレーティングシステムが現われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 機能が不十分なため厳密にはオペレーティングシステムとは呼べずモニターと呼ぶべきものだと筆者は考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:オペレーティングシステムの前段階ともいえるモニターとはなんだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはハードウェアの能力が極めて限られているので、大型汎用機のような機能を望むべくもなく、低レベルな機能しか持たざる得ないという限界があります。1990年代ともなると、高速なCPU、大容量のメモリー、大容量のハードディスクなどハードウェアの能力は格段に上がります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、一方で、そのハードウェア上で動かしているソフトウェアのシステム構造は古い頃から手直しを繰り返してアップグレードしてきたものです。さらにパーソナルな環境ではなく、ネットワークに繋がれ、さらにはインターネットに繋がれるまでになると、玩具の箱から個人のツールとして発展してきた単純なパーソナルコンピュータのモデルではいずれ限界が来てしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように下から上へ向かうトレンドが、まず1つあります。&lt;br /&gt;
&lt;br /&gt;
==== 上から下への流れ ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コンピュータが作られた時から、今日のパーソナルコンピュータが隆盛を究めるまでに至まで常にコンピュータのハードウェアは高価なものでした。&lt;br /&gt;
1960年当時初期までは、コンピュータはプログラムを走らせるために特別なセットアップが必要で、色々なプログラムを走らせることが困難でした。&lt;br /&gt;
高価なハードウェア上でもっと汎用的にプログラムを動かすために作られたシステムが1964年に作られたIBM S/360です。ここで始めて今日的なオペレーティングシステムが作られます。&lt;br /&gt;
汎用機という言葉は、この「汎用的にプログラムを動かすことができるシステム」という所から来ています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:NASAComputerRoom7090.NARA.jpg|left|thumb|300px| 1962年にNASAで使われていた IBM 7090 の写真(NASAサイトより)&amp;lt;ref&amp;gt;NASA の著作権ポリシー http://www.jsc.nasa.gov/policies.html#Guidelines&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
時代は流れ大型汎用機もダウンサイジングの並に流されます。&lt;br /&gt;
まず最初のダウンサイジングで成功したのはDEC社の科学技術計算用コンピュータPDPシリーズやVAXシリーズです。&lt;br /&gt;
これらはミニコンと呼ばれました。これは1970年代後半から80年代後期まで成功を納めます。&lt;br /&gt;
さらに時代は進み、今度はワークステーションの出現です。&lt;br /&gt;
90年代に入るとDEC社のVAXが、SUN MicrosystemsのSUN ワークステーションに置き換わることになります。&lt;br /&gt;
そのダウンサイジングに大きな役目を果たしたのがUNIXです。&lt;br /&gt;
UNIXはワークステーションからスーパコンピュータまであらゆるサイズのコンピュータ上で使えるようになっていました。&lt;br /&gt;
別の言い方をすれば、ワークステーションからスーパーコンピュータでも十分に満足できる今日的オペレーティングシステムの機能をUNIXは兼ね備えているというわけです。&lt;br /&gt;
しかし、まだ業務や科学技術計算で使うコンピュータと、パーソナルで使うコンピュータには価格的にも性能的にも大きな隔たりがありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代後半になるとIA-32 (&#039;&#039;Intel Architecture,32bit&#039;&#039;)のハードウェアに席捲されます。2000年以降は、ダウンサイジングの到着点です。もう個人で使うパーソナルコンピュータも、業務や科学技術計算で使うものも、ハードウェア的には価格的にも、使われている技術にも、処理能力にも線引きが出来できません。2005年では、64bit CPU、デュアルプロセッサ対応、デュアルコアCPUといった最先端のテクノロジーがコモディティ市場 (一般消費者向け市場) に売られている時代になりました。この傾向はこれから先も続きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 考えてみよう : ムーアの法則とは限界を示しているのか、いないのか。限界を示しているとしたらなぜなのか。あるいは、ないならばなぜなのか。尚、ムーアの法則の意味は、オリジナルの意味である集積度の向上と、派生的に多く使われている性能の向上のどちらの意味で取ってもよい。&lt;br /&gt;
&lt;br /&gt;
===  2007年現在の状況 ===&lt;br /&gt;
&lt;br /&gt;
下から上がって来た流れと、上から下がってきた流れがぶつかり、しかもそれがうまく融合していない状態が続いていたという状況で、やっと今は、下からの流れを捨てつつ、上からの流れに追いついたといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
下からの流れがいちばん判りやすいのがMicrosoft社のセキュリティの問題です。&lt;br /&gt;
その主力製品であるWindowsは1つはWindows 95/98/Meという流れがあり、もう1つはWindows NT/2000/XPという流れがあります。&lt;br /&gt;
前者は、パーソナルコンピュータの流れ、後者は大型汎用機の流れです。ちなみにWindows NTを設計したのはDEC でVMSの開発をしていて、Microsoft社にヘッドハンティングされたデビット・カトラーです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上から下がっていたオペレーティングシステムの体系に、下から上がってきたアプリケーション体系を合わせようとしても、なかなかうまくいきません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パーソナルコンピュータでは、使っているのは一人なわけですから、なんでもオールマイティーにアクセスしても一見問題はないように見えます。一方で大きなコンピュータは一人で使っていては、あまりにも高価なので、多人数で使えるなければなりませんし、そうなれば勝手に他人のファイルや、ましてや勝手にシステムの運用に関わる設定など変えてはいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
なんでもアクセスできてしまうパーソナルコンピュータのソフトウェアの方がシンプルかつ簡便な操作を提供できる...と考えても不思議ではありません。&lt;br /&gt;
しかし、便利であったはずの「なんでもアクセスできる」というのがセキュリティの面、特にコンピュータウィルスや脆弱性をついてのシステムへの侵入などクリティカルな問題へ結びつき、それが時代とともに表面化してきました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上からと下からの矛盾が現在のWindowsの根本的な問題となっていました。&lt;br /&gt;
Windows Vista以降では完全にユーザ権限を分離した管理体系による高いセキュリティを持つという能力を提供しています。&lt;br /&gt;
ですが、Windows XP まで動いていたアプリケーションやドライバー類が動かずデベロッパーやユーザが不満を漏らしていたという状況も一方ではありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように必要な安全性を達成するには、下から上へ上がってきたようなレガシーなソフトウェアを切り捨てなければ困難です。しかし、一方で膨大なソフトウェア資産があるわけです。この矛盾に終止符を打つのは大変長い時間がかかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : 1980年代のスーパーコンピュータやパソコンと呼ばれていたコンピュータの処理能力は、どの程度のものだったのだろうか。その能力の向上はどうだったのだろうか。&lt;br /&gt;
&lt;br /&gt;
== 何をさしてオペレーティングシステムと呼ぶのか ==&lt;br /&gt;
=== 広義と狭義の議論 ===&lt;br /&gt;
&lt;br /&gt;
[[File:Layer-of-System-2.png|thumb|right|400px|System Layer]]&lt;br /&gt;
&lt;br /&gt;
コンピュータ上で動いているソフトウェアのどの部分を指してオペレーティングシステムと呼ぶべきないのか、ということの定義を確認しましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここでは、一番最下層をハードウェアとして、次にあるのが[[カーネルの構造と機能|カーネルの層]]、その次が汎用に使われるシステムユーティリティの層、そして、特定目的のためにユーザが利用するアプリケーションの層というモデルを考えてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムと、システムユーティリティの両方を1つのまとまりとして、システムソフトウェアと呼びます。「システムを動かすのに最低限必要なソフトウェアセット」という広い意味で捉えたオペレーティングシステムであれば、このシステムソフトウェアがオペレーティングシステムと同意語であると言えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし「最小限必要な」という定義は、かなり曖昧な表現です。なぜならば、ここには「&#039;&#039;&#039;&#039;&#039;誰が、どのように使うか&#039;&#039;&#039;&#039;&#039;」ということが抜けているからです。&lt;br /&gt;
この部分を拡張していけば、たとえば「ワードブロセッシングを行いたい人が使うためのコンピュータ」という場合は「バンドルされているワードプロセッサのプログラムも含めてオペレーティングシステムである」という奇妙な結論が導かれてしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この「パッケージを購入した時にバンドルされているアプリケーション群が最小限のセットなので、これがオペレーティングシステムである」という誤解&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://ja.wikipedia.org/w/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;amp;oldid=29875236 日本語版wikipedia]ではウェブブラウザや時計などのアクセサリーも広義のオペレーティングシステムだということを書いていますが、そんなことをテストに書いて点数をくれる先生は極めて少数派でしょう。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は一般には多いようです。&lt;br /&gt;
もしこれが正しいとするならば、これではゲームのソリティアもオペレーティングシステムに含まれることになるので、やはり奇妙な結論と言えます。&lt;br /&gt;
このような表現での「最小パッケージ」とはGNU/Linuxのディストリビューションのデフォルトイントール環境にあたるもので、このオペレーティングシステムの定義を採用するとなると、世の中にはおびただしい数のオペレーティングシステムの種類&amp;lt;ref&amp;gt; オープンソース系オペレーティングシステムののディストリビューションを紹介する https://distrowatch.com  には実に様々なディストリビューションが紹介されています。&amp;lt;/ref&amp;gt;が存在することになります。このような定義を用いると、このような奇妙な結果が導き出されてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では逆に、ここは確実にオペレーティングシステムだろうと言える部分を考えてみます。まずカーネルは当然入ります。ユーザが使うということであれば、&lt;br /&gt;
シェルなども必要です。なぜならシェルがないとコマンドを入力できません。当然ユーザを認証するためのログインに関連するソフトウェアが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : カーネルとそれ以外のソフトウェアの切り分けは、実行されるプロセスの実行モードが、どの状態で動いているかで区別します。プロセスの実行モードが、カーネル・モード（UNIX以外のシステムによっては特権モード、スーパーバイザ・モード、あるいはマスタ・モードとも呼ばれる) で動作しているか、ユーザ・モード ( 非特権モード、プロブレム・モード、あるいはスレーブモードとも呼ばれる)で動作しているかどうかです。実行モードに関しては、実行とプロセスに関する話題の時に改めて説明します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どれくらいのものが最初に用意されるのか、Debian GNU/Linux 6.0を例にして調べてみました。&lt;br /&gt;
&lt;br /&gt;
  ディレクトリ名      コマンド数&lt;br /&gt;
  /bin              95&lt;br /&gt;
  /sbin             110 &lt;br /&gt;
  /usr/bin          452&lt;br /&gt;
  /usr/sbin         107&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 :  2011年時点で最新のDebian GNU/Linux 6.0 を参考にしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコマンド数も先に述べたようにすべてが必要であるとは限りません。最小限インストールの状態のDebian GNU/Linuxに入っているコマンド数を数えたに過ぎません。&lt;br /&gt;
しかしながら、いくつかのコマンドとそのコマンドで利用されるライブラリ群はオペレーティングシステムには必要になるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では、グラフィカルインタフェース(GUI)を提供するためのウィンドウシステムはオペレーティングシステムに入るのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一般的なUNIXシステムでは、GUIがなくても当然動きますし、サーバシステムではGUIなどは必須ではありません。もちろん先程のDebian GNU/Linux最小限セットの中にはX Window Systemは入っていません。逆にパーソナルコンピュータ用のオペレーティングシステムと呼び販売されているタイプのものではウィンドウシステムは切り離すことができないコンポーネントとなっています。&lt;br /&gt;
&lt;br /&gt;
=== 揺らぐ定義 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot-Oracle VM VirtualBox.png|thumb|right|450px|コンソールでTOPを実行]]&lt;br /&gt;
&lt;br /&gt;
右図は仮想マシンに&lt;br /&gt;
[https://www.virtualbox.org/ VirtualBox]&lt;br /&gt;
を使い、&lt;br /&gt;
[https://www.debian.org/ Debian GNU/Linux] 6.0&lt;br /&gt;
を最小限インストールし立ち上げてみた状態です。&lt;br /&gt;
もちろんGUIはインストールしていません。なぜならGUIが存在しなくともきちんとコンピュータは動くからです。&lt;br /&gt;
Debian GNU/Linux 6.0 はデスクトップやラップトップ、あるいはサーバに使われるディストリビューションで、組み込み用のものではありません。&lt;br /&gt;
top コマンドを使い、メモリや実行中のプロセスが、どのような状態になっているか観察してみました。&lt;br /&gt;
用意しているメモリは 128MB ですが、この状態で使われている記憶領域は約 26MB しか使っていません。&lt;br /&gt;
df を使ってディスクの利用状況を見てみると、最小のインストールでは約 645MB しか使っていません。&lt;br /&gt;
最小限のセットを考えた場合、このように小さいメモリでも動くことができます。&lt;br /&gt;
この程度の資源でも(英文であれば、ですが）十分にテキストを編集し、スペルをチェックし、フォーマットし、さらにプリンタに出力ができます。&lt;br /&gt;
十分に「パーソナルな」コンピュータだといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように使い方によって、あるいはユーザのニーズによって「最小限の」という言葉を使って表現している広義のオペレーティングシステムの意味は揺らぐのがわかるかと思います。&lt;br /&gt;
しかしながら揺らぐからといって無限に定義を拡大していくような問題でもありません。&lt;br /&gt;
そのあたりがグラデーションのようになっていて簡単には線引きないのが特徴だといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
==  コンピュータを仮想化させる == &lt;br /&gt;
[[File:Virtualization.png|thumb|right|450px|Virtualization]]&lt;br /&gt;
我々が、アプリケーションプログラムを使う時、プログラムがコンピュータを占有しているように見えます。ユーザが他にどれだけのプログラムが実行されているかなど気にすることなく使うことができます。&lt;br /&gt;
&lt;br /&gt;
実際は、オペレーティングシステムが、リソースを抽象化し、プログラムに使えるリソースを割り当てることをします。つまり、プログラムは、「仮想化されたコンピュータ」を割り当てられることになります。ユーザに使用許可（パーミッション）が与えられている限り利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
UNIXでは、どのような仮想化の例があるのでしょうか? 典型的な例をいくつかあげて見ましょう。&lt;br /&gt;
&lt;br /&gt;
* CPUのリソースは、プログラムに対し、プロセスという単位で割り当てられます。&lt;br /&gt;
&lt;br /&gt;
* プログラムの使う記憶空間のリソースは、仮想記憶によりコントロールされます。仮想記憶の機構により、主記憶だけではなく、補助記憶装置も使って、主記憶よりも大きい記憶空間を作ることが可能です。その中から、プログラムが必要な大きさの記憶空間リソースを割り当ています。&lt;br /&gt;
&lt;br /&gt;
* 永続的な記憶を保管しておくために、ファイルという抽象的なデータの保管メカニズムを使います。そのファイルを効率的かつ統一的に扱うために、ファイルシステムを作ります。ファイルシステムは、主記憶と補助記憶装置を使って、ファイルのリソースを提供します。&lt;br /&gt;
&lt;br /&gt;
* 入出力装置のリソースのために、デバイスファイルという入出力装置を抽象化した入出力リソースを提供しています。&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
:&#039;&#039;&#039;捕捉&#039;&#039;&#039; さらに&lt;br /&gt;
:[http://www.cl.cam.ac.uk/Research/SRG/netos/xen/ Xen]、[http://www.vmware.com/  VMware]、[https://www.virtualbox.org/ VirtualBox]のようにハードウェア側を抽象化し、1つのハードウェア上に複数のオペレーティングシステムを動かすバーチャルマシンのシステムもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 抽象化の例 ====&lt;br /&gt;
&lt;br /&gt;
UNIXの上で次のコマンドを実行すると端末にHelloと表示されます。これは文字列&amp;quot;Hello&amp;quot;を出力し、その出力先をファイル&lt;br /&gt;
/dev/tty&lt;br /&gt;
への入力するという働きをします。ファイル（デバイスファイルと呼びます）&lt;br /&gt;
/dev/tty&lt;br /&gt;
というのは、自端末を抽象化したものです。&lt;br /&gt;
いくつも端末のウインドウを開いて別々のシェルで行っても、ほかの端末には表示せず、自分の端末のみに出力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % echo &amp;quot;Hello&amp;quot; &amp;gt; /dev/tty&lt;br /&gt;
 Hello&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....E、は、オペレーティングシステムから利用可能なリソースを割り当てられ、その中で実行しています。しかし、アプリケーションA、B,....は、割り当てられたリソースのコントロールを意識しません。&lt;br /&gt;
例えば、プログラムがデータを補助記憶装置にファイルの形でデータを残そうとした時、プログラムが、補助記憶装置に使われているハードウェアを直接的にコントロールする必要はありません。つまり、1つのプログラムは、1つの仮想化されたコンピュータで動いているように見えるわけです。&lt;br /&gt;
&lt;br /&gt;
==== 不完全なリソース管理 ====&lt;br /&gt;
&lt;br /&gt;
もし、直接的にコントロールするはずのないリソースをユーザのアプリケーションプログラムがオペレーティングシステムを飛び越して直接的にコントロールできるようなことがあればどうなるのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
例えば、ユーザのアプリケーションプログラムにバグがあり、割り当てられたリソース以外のリソースを不用意に利用してしまうようなことを許すような不完全なリソース管理のオペレーティングシステムだとどうなるでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....は、オペレーティングシステムから割り当てられたリソースを使っているわけですから、オペレーティングシステムの知らない所で、割り当てられていないリソースに勝手なことをされては、一貫性が保てません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代のパソコンのオペレーティングシステム(と呼ばれていたもの)は、このような不完全なリソース管理の能力しか持っていませんでした。これらはオペレーティングシステムと呼ぶに値するのか非常に疑問で、本来はまだオペレーティングシステムまで発展していない前段階の機能であるハードウェアを監視するモニタと呼ばれるものに分類するのが適切であるように思えます。&lt;br /&gt;
&lt;br /&gt;
==== さらなる仮想化の例 ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== mmapとファイル =====&lt;br /&gt;
&lt;br /&gt;
例えば、UNIXのmmapと呼ぶ機能です。最近のUNIXは、[http://uc.h2np.net/index.php/%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86#mmap mmap]という機能を使ってプログラムは、ファイルを記憶空間に張り付ける (マップする) ことができます。主記憶、補助記憶装置のリソース区別が更に抽象化されプログラムの中で使える記憶空間としてのリソースとなります。もちろん通常のプログラムに割り当てられた記憶領域として、読み込み、書き込みすると、その内容がファイルに反映されます。さらに、ファイルという形で、複数のプロセスから、共有することができます。&lt;br /&gt;
&lt;br /&gt;
===== VFSからデバイスドライバまで =====&lt;br /&gt;
[[File:Filesystem-layer-1.png|thumb|right|400px|File System Layer]]&lt;br /&gt;
[[ファイルシステム]] をさらに抽象化するLinuxのファイルシステムを紹介しましょう。&lt;br /&gt;
ファイルを書き込む説明で「ハードディスクに書き込む」という表現をみたことはないでしょうか。&lt;br /&gt;
目の前にあるパソコン本体のみを考えるならば、このモノに書き出すというので説明は十分なのかも知れませんが、ファイルを書き込む・読み込むというのはもっと抽象的な動作をします。&lt;br /&gt;
&lt;br /&gt;
Linuxのファイルシステムは、上位にVFS (Virtual  File System)が存在し、その下に、FAT、ext4、JFS、XFS、NFS、その他のファイルシステムをもち、さらにその下にバッファキャッシュがあり、さらに下にデバイスドライバがあるといった、何重もの層を重ねる形になっています。&lt;br /&gt;
プログラムは、Linuxのファイルを扱っているだけで、その下がFATのファイルシステムやJFSのファイルシステムであるか、あるいはネットワーク経由でファイルシステムを使うことができるNFSなのかを知らなくても利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
下層には、補助記憶装置との入出力効率を改善するために、バッファキャッシュというクッションをおいてあります。&lt;br /&gt;
さらなる下層には、ハードディスクやフラッシュメモリ (例えばUSBメモリやSDカードなど)といった記憶するためのハードウェア、あるいはNFSのようにネットワークを経由して使うためのネットワークハードウェアをコントロールするためのデバイスドライバの層があります。&lt;br /&gt;
ファイルの情報が最終的にハードディスクに書かれるとしても、ファイルを書き込む動作を行った時点で、まだハードディスクにかかれているわけではありません。&lt;br /&gt;
このようなことにより、たぶん一度や二度は経験したことがあるかも知れませんが、突然、機材の電源を停止すると永続的な情報を保持するためのエリア(ハードディスクやUSBメモリなど)にかかれていなかったファイルの情報は消えてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % sync;sync;sync&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sync&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
syncを三回するのは &amp;quot;In the name of the Father, and of the Son, and of the Holy Spirit.(父と子と精霊の御名において)&amp;quot;と唱えて強制的にハードウェアリセットをするためだとむかし誰かに教わった。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
はバッファキャッシュなどにある情報を含めてすべてデバイスに同期させるコマンド。&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
このように重層的な構造にすることによって、抽象化を図り、かつどの層が変化しようとも、上位の層がその違いを吸収するような形になっています。またこのような枠組みにより柔軟に機能・モジュールを追加、変更することが出来る仕組みになっています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|1]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E9%96%93%E9%80%9A%E4%BF%A1&amp;diff=1762</id>
		<title>プロセス間通信</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E9%96%93%E9%80%9A%E4%BF%A1&amp;diff=1762"/>
		<updated>2024-12-12T11:53:11Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* System V IPC */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== IPCとは ==&lt;br /&gt;
&lt;br /&gt;
プロセス実行中に他のプロセスと通信を行うための機構を考えます。通信ということでは2つの方法を挙げることができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*  ローカルマシン内（もちろん動いているカーネルは1つという前提）で動作しているプロセス間での通信。&lt;br /&gt;
&lt;br /&gt;
*  ネットワークを経由して通信するネットワーク通信。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
本章では前者のローカルマシン内での通信を取り上げます。もちろんローカルマシン内で動作するプロセス同士でもネットワーク経由と同じようにTCP/IPを使って通信できますが、本章のプロセス間通信の説明からはTCP/IPは除いておきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここでのプロセス通信(InterProcess Communication / IPC )&amp;lt;ref&amp;gt; LinuxのIPCについては次の発表スライドが参考になります。 Michael Kerrisk, &amp;quot;An introduction to&lt;br /&gt;
Linux IPC&amp;quot;,  linux.conf.au 2013 http://man7.org/conf/lca2013/IPC_Overview-LCA-2013-printable.pdf &amp;lt;/ref&amp;gt;とは、名前つきパイプ(named pipe)、pipe、UNIXドメインソケット(ローカルIPC)、&lt;br /&gt;
セマフォー&amp;lt;ref&amp;gt;Linuxのセマフォーに関しては次のWebサイトが詳しい。 http://www.linuxdevcenter.com/pub/a/linux/2007/05/24/semaphores-in-linux.html&amp;lt;/ref&amp;gt;やあるいはシェアードメモリなどを指しています。これらにより高速にプロセス間でデータをやりとりするためのメカニズムと捉えます。Linuxでは、&lt;br /&gt;
System Vで使われていたプロセス間通信の機能、4.2BSDで採り入れられたソケット、名前つきパイプが使えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 単一カーネル内ではIPのルーティング機能などの不必要な情報の付加や処理を行わずに済むので、その点から「高速にデータをやりとり」と書いていますが、経験的には、実際の速度差は実装によってずいぶん違うので、一概にどれぐらい違うかは簡単にはいえません。&lt;br /&gt;
&lt;br /&gt;
== System V IPC ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセス間通信の機能というと、System Vで使われていたプロセス間通信の機能(System V IPC)のセマフォー&amp;lt;ref&amp;gt;セマフォーとは、元々は列車運行で列車が単線の区間に入ることを許されているか、あるいは待つのかを示す信号機なのだそうです。&amp;lt;/ref&amp;gt;(semaphore)、メッセージキュー(message&lt;br /&gt;
queues)、シェアードメモリ(shared memory)が有名です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ソフトウェアの世界では、複数のプロセスが同じ資源の競合を避けるために、使われる機能で、たとえば複数のプロセスが同時にファイルを書き込みするタイミングが同じになってしまわないように、セマフォを使って待ちます。&lt;br /&gt;
セマフォは(ファイルのロックなどを使うよりも）高速に処理できるので、たとえばデータベースのようなアプリケーションでの処理のロックなどに使われています。&lt;br /&gt;
しかし、同様な処理はmmapを使っても可能ですので、今日ではセマフォがなくては実装ができない、というわけではありません。むしろ、互換性のために残していると考えた方が良いでしょう。また今日ではSystem V IPCは、相対的に「重い」処理と考えられています。&lt;br /&gt;
一方、POSIX IPC はマルチスレッドで安全であり、かつ、System V IPCより軽量なのでPOSIX IPCの利用が推奨されています。&amp;lt;ref&amp;gt;IBMのdeveloper worksのサイトの中にある &amp;quot;[https://www.ibm.com/developerworks/jp/linux/library/l-semaphore/index.html System V のセマフォー API を使用して POSIX のセマフォー API を実装する]&amp;quot;  の本文中に「POSIX のセマフォーは System V のセマフォーよりもはるかに軽量」という記述も存在する。&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;　  Oracle Solaris 10 1/13 Information Library (日本語)　のドキュメントにも「[https://docs.oracle.com/cd/E38900_01/html/E38879/svipc-posixipc.html POSIX セマフォーは、System V セマフォーより軽量です。] 」という記述がある。 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 semget (2)           - セマフォーの獲得&lt;br /&gt;
 semctl (2)           - セマフォーの制御&lt;br /&gt;
 semop (2)            - セマフォーの設定&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
System V IPCを使ってのメッセージキューは古いアプリケーションを動かすための互換性のために残されているようなもと考えても良いレベルになって来ています。今日では新規のプログラムに使うような場面を見かけたことがありません。最近ではメッセージキューを使う所を名前つきパイプで済ますことができます。シェアードメモリもmmapが使えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのカーネルが2.6以降ではPOSIX IPCが使えるようになりました。新しくプログラムを作る場合で、メッセージキューなどを使いたい時はSystem V IPCではなくPOSIX IPCを使うべきでしょう。&lt;br /&gt;
&lt;br /&gt;
== POSIX IPC ==&lt;br /&gt;
&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
== 名前つきパイプ (named pipe) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
その前にパイプを説明しましょう。コマンドラインでのシェルが持つパイプは、前のコマンドの標準出力を後ろのコマンドの標準入力にするというものです。使い勝手は、まるっきりファイルです。&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
現在のディレクトリにあるファイル数をカウントする&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % ls  | wc  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このようなプロセス間で一方向に書き出し、読み込みをするプログラムを書く時は、UNIXの初期からあるシステムコールとしてpipe(2)を使って実現します。 &lt;br /&gt;
pipe(2) は、プロセス中で2つの要素を持つファイルデスクリプタ配列に対して、1つは書き込み、もう1つは読み込みのディスクリプタを与えるというものです。このペアを作っておき、プロセスがフォークすると、1つのプロセス側は書き込み、もう一つのプロセス側は読み込みができるようになります。もちろん一方向にしかデータは流れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、名前つきパイプは、それまでのプロセスがフォークして資源を継承するしかできない一方向に流れるパイプとは違い、2つの完全に独立に存在しているプロセス間でデータをやり取りするために作られたものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFO(First-In-First-Out)である名前つきパイプを作ります。これはファイルのように名前でアクセスできるFIFOの性質を持った双方向パイプを作ります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずコマンド mkfifo で名前つきパイプのファイルを作ります。ファイルといってもアクセスのために名前だけあって実態はパイプです。 ls -l で見ると先頭がpがあるので、名前つきパイプであることがわかります。あとls -Fとしてみると、npの後ろに&amp;quot;|&amp;quot;がついて出力されます。これは名前つきパイプ(FIFO) のファイルであるという意味です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
名前付きパイプのファイルを作る&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ mkfifo np&lt;br /&gt;
 $ ls -l np&lt;br /&gt;
 prw-r--r--    1 hironobu hironobu        0 Dec 16 21:58 np&lt;br /&gt;
 $ ls -F np&lt;br /&gt;
 np|&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
この状態で2つのshellウインドウを開いてみてください。一つはnpを読む、もう一つではnpに書き込むことをしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
shellウインドウ1&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cat np&lt;br /&gt;
 abcdef &amp;lt;-- 表示される&lt;br /&gt;
 123456 &amp;lt;-- 表示される&lt;br /&gt;
 $      &amp;lt;-- 終了する&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
shellウインドウ2&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cat &amp;gt; np&lt;br /&gt;
 abcdef &amp;lt;--入力&lt;br /&gt;
 123456 &amp;lt;--入力&lt;br /&gt;
 ^D     &amp;lt;-- ^Dで終了&lt;br /&gt;
 $ &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ここでは判りやすいように一方向にデータを送っている例を出していますが、このようにファイル名でアクセスするようにしてプロセス間の通信が出来るというのは、実にUNIXらしいやり方です。プログラム中から名前つきパイプを作る時はユーザ関数 mkfifo(3)で作れます。&lt;br /&gt;
&lt;br /&gt;
== UNIXドメインソケット (ローカルIPC) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはTCP/IPネットワーク接続の機能のインタフェースと同じものを用意して、しかし、データはローカルなプロセス間通信に使おうというものです。元々はUNIXドメインソケットという形でBSD 4.xに組み込まれましたが、Posix はUNIXに依存しないのでローカルIPC という呼び方をしています。しかし、少なくとも筆者の知っている範囲のUNIXユーザはUNIXドメインソケットと読んでいるので、カッコつきで(ローカルIPC)としました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: POSIXでは「ローカルIPC」という呼び方をしますが、UNIX流ではUNIXドメインソケットと呼びます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
socket(2)、bind(2)、accept(2)のようにTCP/IPの通信を行うやり方は、TCP/IPが現れる以前のUNIXとはセマンティクス（意味的なもの）が違います。UNIXが、すべてを名前空間でアクセスしようとするのに対して、TCP/IP のような通信系のやり方は、一々、IPアドレスやポート番号を指定しなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 int sockfd;&lt;br /&gt;
 struct sockaddr_un addr;&lt;br /&gt;
 ...&lt;br /&gt;
 sockfd=socket(AF_LOCAL, SOCKET_STREAM,0);&lt;br /&gt;
 ...&lt;br /&gt;
 addr.sun_family = AF_LOCAL;&lt;br /&gt;
 strcpy(addr.sun_path, &amp;quot;/tmp/mysocket&amp;quot;);&lt;br /&gt;
 bind(sockfd,&amp;amp;addr,SUN_LEN(addr));&lt;br /&gt;
 ....&lt;br /&gt;
&lt;br /&gt;
ソケットをAF_LOCALで作成し、sun_familyをAF_LOCALに指定し、sun_path の部分にファイルパスを書きバインドすると、そのパスにファイルに見えるソケットが出来ます。こうすれば、あとのデータの送信／受信に関係するプログラムの構造はTCP/IPと同じに作れます。その面ではインターネット経由でアクセスするプログラムとローカルにアクセスするプログラムが同じ構造で作れる利点があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ログを出力するデバイスのように見せかけているソケット&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -lF /dev/log&lt;br /&gt;
 srw-rw-rw-    1 root     root            0 Aug 23 14:13 /dev/log=&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはログデーモンがオープンしているソケットです。しかしながら、パス名で見えていても、ファイルではないので、通常のファイルを扱うコマンドでアクセスしてもエラーになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
かな漢字サーバWnnのソケットをcatで見てみる&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -lF /tmp/jd_sockV4 &lt;br /&gt;
 srwxr-xr-x    1 wnn      nogroup         0 Sep 21 13:48 /tmp/jd_sockV4=&lt;br /&gt;
 $ cat /tmp/jd_sockV4 &lt;br /&gt;
 cat: /tmp/jd_sockV4: No such device or address&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらはIPスタックを経由しません。IPは複数の独立したホストがあり、ネットワーク構築された世界をIPパケットが中継されていくモデルです。そのためにIPパケットを処理するためには、そのための処理がなされます。一方、UNIXドメインソケットには、そんな付加する情報をつけたり処理したりする必要はありません。よって高速に処理することが可能になります。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL:  http://uc2.h2np.net/i/25.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1761</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1761"/>
		<updated>2024-10-24T13:20:25Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* CFS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  GNU/Linux上で円周率の計算をおこなう http://h2np.net/pi/&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下3300万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、数十分、あるいは数時間という具合に長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;追記: その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
==== スケジューラのチューニング ====&lt;br /&gt;
&lt;br /&gt;
スケジューラのチューニングに関しては下記の情報が参考になります。&lt;br /&gt;
&lt;br /&gt;
* SUSE [https://www.belbel.or.jp/opensuse-manuals_ja/cha-tuning-taskscheduler.html タスクスケジューラのチューニング]&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux 9 [https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/pdf/monitoring_and_managing_system_status_and_performance/red_hat_enterprise_linux-9-monitoring_and_managing_system_status_and_performance-ja-jp.pdf 第30章 スケジューリングポリシーの調整]&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が低く、大きいものが実行優先順位が高くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB&amp;diff=1760</id>
		<title>パスワードファイル</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB&amp;diff=1760"/>
		<updated>2024-08-22T16:16:48Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* パスワードの生成 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
本章を読む前に、まずパスワードを使った認証メカニズムについての一般論である[[システムにおけるパスワード管理の概要]]のページを先に読んでから本章に進むことをお薦めします。&lt;br /&gt;
&lt;br /&gt;
== パスワードファイル /etc/passwd == &lt;br /&gt;
&lt;br /&gt;
ユーザIDとアカウント名を対応させているのがパスワードファイル&lt;br /&gt;
/etc/passwdです。パスワードファイルのフォーマットは次の通りです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* パスワードエントリのフォーマットのフィールドは&amp;quot;:&amp;quot;で区切られる&lt;br /&gt;
* アカウント名 :   ログイン時に使用するアカウント名&lt;br /&gt;
* パスワード : パスワードをハッシュ値に置き換えたもの&lt;br /&gt;
* ユーザID :  ユーザを認識するための数値&lt;br /&gt;
* グループID : グループを認識するための数値&lt;br /&gt;
* コメントフィールド([[GECOSフィールド]]) : 名前等の情報を記述するフィールド&lt;br /&gt;
* ホームディレクトリ : ホームディレクトリ&lt;br /&gt;
* シェルパス :  利用するシェルのパス、もしくはシェルに相当するコマンド&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 /etc/passwd の エントリー例&lt;br /&gt;
 hironobu:x:1825:2000:Hironobu SUZUKI,,,:/home/hironobu:/bin/bash&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このエントリー例は実際運用しているシステムのパスワードファイルから抜き出したものです。&lt;br /&gt;
パスワードのフィールドは&amp;quot;x&amp;quot;が入っています。&lt;br /&gt;
これは利用しているシステムがシャドーパスワードを導入しているからです。&lt;br /&gt;
そのため現状のGNU/Linuxディストリビューションでは、一般ユーザが(ハッシュ値となっている)パスワードを直接参照することはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
元々のパスワードファイルには2つの情報が入っています。&lt;br /&gt;
一つは公開して誰でも知って良い情報、もう一つは知られてはいけない情報です。&lt;br /&gt;
その知られてはいけない情報とはパスワードの情報です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== パスワードの生成 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もちろんこのパスワードは、すでに一方向性ハッシュ関数によって撹拌されている値となってなっています。&lt;br /&gt;
したがって、パスワードファイルの中にあるすでに撹拌されているパスワードのハッシュ値だけ持っていても、&lt;br /&gt;
そこから元のパスワードを逆算することはできません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:補足 パスワードの生成や管理についての詳しい説明は「[[システムにおけるパスワード管理の概要]]」の章を参照のこと。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パスワードが完全なランダムであった場合&amp;lt;ref&amp;gt;ただし辞書攻撃などが可能な類推可能な文字からなるパスワードであれば、現在ではほぼ一瞬で見つけることが出来ます。&amp;lt;/ref&amp;gt;、総当たりで見つける方式しか使えません。&lt;br /&gt;
ただし、このままでは同じパスワード入力が同じハッシュ値になってしまいます。&lt;br /&gt;
パスワードのパターンを事前に計算し、逆引きのテーブルを用意することが可能となってしまします。&lt;br /&gt;
そのため、同じパスワード入力が同じハッシュ値にならないようにSalt（塩）と呼ぶランダムな初期値を加えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
現在のGNU/Linuxではディストリビューションにより、オリジナルのUNIXが使っていたパスワードのメカニズムをベースとしたパスワード認証の方法を用いているものと、[http://www.linux-pam.org/ Linux-PAM]と呼ばれる包括的なパスワード認証のためのフレームワークを用いているものがあります。近年ではメジャーなディストリビューションの多くはLinux-PAMを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIX オリジナルの方法では暗号化するためのDESを用いたメッセージ認証コード方式DES-CBC-MAC&lt;br /&gt;
&amp;lt;ref&amp;gt; CBC-MACに関しては[http://en.wikipedia.org/wiki/CBC-MAC wikipedia(英語版)]を参照のこと。 &amp;lt;/ref&amp;gt;&lt;br /&gt;
を一方向性ハッシュ関数として利用してます。&lt;br /&gt;
&amp;lt;ref&amp;gt;このDES-CBC-MACの暗号学的安全性に関しての議論は https://www.iacr.org/cryptodb/data/paper.php?pubkey=541 , http://www.cypherpunks.ca/~iang/pubs/crypt3-asia00.pdf を参照のこと。&amp;lt;/ref&amp;gt;&lt;br /&gt;
glibcで実装されているパスワード認証のためのアルゴリズムでは、DES-CBC-MACではなく一方向性ハッシュ関数としてMD5、SHA1やSHA-256を使います。&lt;br /&gt;
オリジナルの方法では、DESを使う場合は25回繰り返して計算します。glibcでは一方向性ハッシュ関数を使う場合は最低1000回繰り返して計算します。&lt;br /&gt;
&amp;lt;ref&amp;gt;これは計算負荷をあげているものですが、これはDESを使っていた時は乱雑さとして有効となるビット数が少なかったためで、一方向性ハッシュ関数の場合、暗号学的には繰り返して計算負荷をあげるよりもランダムなパスワード文字数を増やす方法の方が優れています。&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[ファイル:Password-hash.png|450px|thumb|center|パスワードの生成]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 捕捉 : 図中では「暗号化したパスワード」という表現を使っていますが、本来は復号することができないので暗号化という言葉は暗号の考え方からして適切ではありません。しかし慣用的に「暗号化したパスワード」という言葉を使うので、ここではあえて使っています。正しくは「パスワードのハッシュ値」あるいは「パスワードのMAC値」です。&lt;br /&gt;
&lt;br /&gt;
=== パスワードの保管 ===&lt;br /&gt;
&lt;br /&gt;
オリジナルのUNIXではパスワードファイル/etc/passwdの中にユーザ名やユーザIDと共にパスワードのハッシュ値が格納されており、誰でも参照することが可能でした。&lt;br /&gt;
攻撃側は、パスワード候補を用意し、その出力をパスワードファイルの中にあるパスワードのハッシュ値と比較することによって効率的にパスワードを見つけることが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
そこで変換後のパスワードを一般ユーザが直接は参照できない別ファイルに取っておき、認証するコマンドやメンテナンスのコマンドのみがアクセスできるようにしました。これがシャドーパスワードの仕組みです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l  /etc/shadow&lt;br /&gt;
 -rw-r-----    1 root     shadow        789 Oct 22  2003 /etc/shadow&lt;br /&gt;
 $ ls -l /usr/bin/passwd&lt;br /&gt;
 -rwsr-xr-x    1 root     root           24616 Nov  3 04:56 /usr/bin/passwd&lt;br /&gt;
 $ ls -l /usr/bin | grep shadow&lt;br /&gt;
 -rwxr-sr-x    1 root     shadow      32584 Nov  3 04:56 chage&lt;br /&gt;
 -rwxr-sr-x    1 root     shadow      15976 Nov  3 04:56 expiry&lt;br /&gt;
 -rwxr-sr-x    1 root     shadow       6628 Jun 28 05:20 kcheckpass&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1759</id>
		<title>メインページ</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1759"/>
		<updated>2024-08-08T09:04:46Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[UNIXオペレーティングシステム]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1758</id>
		<title>メインページ</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1758"/>
		<updated>2024-08-08T09:04:14Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: UNIXオペレーティングシステムへの転送ページ&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT[[UNIXオペレーティングシステム]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1757</id>
		<title>メインページ</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1757"/>
		<updated>2024-08-08T09:00:37Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: UNIXオペレーティングシステム へのリダイレクトを解除しました&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[UNIXオペレーティングシステム]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1756</id>
		<title>メインページ</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1756"/>
		<updated>2024-08-08T08:56:09Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT[[UNIXオペレーティングシステム]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1755</id>
		<title>メインページ</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1755"/>
		<updated>2024-07-29T04:31:37Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: UNIXオペレーティングシステムへの転送ページ&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[UNIXオペレーティングシステム]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1754</id>
		<title>メインページ</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8&amp;diff=1754"/>
		<updated>2024-07-29T04:30:01Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: ページの作成:「__NOTOC__  このサイトはGNU/Linuxを通してUNIXオペレーティングシステムを学ぶ授業で使うテキストを掲載しています。詳しくはこのサイトについてのページを参照ください。また何故GNU/Linuxを取り上げるのかは「なぜUNIXオペレーティングシステムの授業にGNU/Linuxを取り上げるのか」を参照してください。  === テキストの目次 ===  * 第一章 オペ…」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
このサイトはGNU/Linuxを通してUNIXオペレーティングシステムを学ぶ授業で使うテキストを掲載しています。詳しくは[[このサイトについて]]のページを参照ください。また何故GNU/Linuxを取り上げるのかは「[[なぜUNIXオペレーティングシステムの授業にGNU/Linuxを取り上げるのか]]」を参照してください。&lt;br /&gt;
&lt;br /&gt;
=== テキストの[[目次]] ===&lt;br /&gt;
&lt;br /&gt;
* 第一章 [[オペレーティングシステムとは何か]]&lt;br /&gt;
** 第一章:補遺:1 [[UNIXとは何か]]&lt;br /&gt;
** 第一章:補遺:2 [[OS誕生からLinuxまでの歴史]]&lt;br /&gt;
* 第二章  [[実際にGNU/Linuxを使ってみよう]]&lt;br /&gt;
** 第二章:補遺:2 [[Ubuntuインストール方法]]&lt;br /&gt;
** 第二章:補遺:3 [[Ubuntu Live CD]]&lt;br /&gt;
* 第三章 [[システム環境を考えてみる]]&lt;br /&gt;
* 第四章 [[カーネルの構造と機能]]&lt;br /&gt;
* 第五章 [[プロセス管理]]&lt;br /&gt;
** 第五章: 補遺:1 [[プロセスのタイムスライスの値を計測する]]&lt;br /&gt;
** 第五章: 補遺:2 [[マルチプロセッサとプロセス]]&lt;br /&gt;
* 第六章 [[記憶管理]]&lt;br /&gt;
** 第六章: 補遺:1 [[Linuxのswapについて私が知っている二、三の事柄]]&lt;br /&gt;
* 第七章 [[デバイススペシャルファイル]]&lt;br /&gt;
** 第七章: 補遺:1 [[Linux LVM]]&lt;br /&gt;
* 第八章 [[ファイルシステム]]&lt;br /&gt;
* 第九章 [[ユーザ権限とアクセス制御]]&lt;br /&gt;
** 第九章: 補遺:1 [[システムにおけるパスワード管理の概要]]&lt;br /&gt;
** 第九章: 補遺:2 [[パスワードファイル]]&lt;br /&gt;
* 第十章 [[プロセス間通信]]&lt;br /&gt;
* 第十一章 [[TCP/IP]]&lt;br /&gt;
** 第十一章:補遺:1 [[アプリケーションサーバ]]&lt;br /&gt;
&lt;br /&gt;
テキストの[[目次]]はこちらからも参照できます。&lt;br /&gt;
&lt;br /&gt;
=== QRコード ===&lt;br /&gt;
&lt;br /&gt;
このページへのQRコードです。&lt;br /&gt;
iPhone や Android からアクセスする際にお使いください。&lt;br /&gt;
&lt;br /&gt;
[[image:QRcode.png|150px]]&lt;br /&gt;
&lt;br /&gt;
=== 各種資料 ===&lt;br /&gt;
&lt;br /&gt;
* [[各種資料]]&lt;br /&gt;
* [[公開されている各種UNIX関連本]]&lt;br /&gt;
* [[NeXus2016カンファレンス]]&lt;br /&gt;
&lt;br /&gt;
=== 過去の資料 ===&lt;br /&gt;
&lt;br /&gt;
* [[2007年リチャードストールマン講演会]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
過去に掲示した内容等は[[過去掲示分]]からもたどれます。&lt;br /&gt;
&lt;br /&gt;
== その他 ==&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: http://uc2.h2np.net/i/a6.html&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
著者への [http://uc2.h2np.net/index.php/Contactpage コンタクト]&lt;br /&gt;
&lt;br /&gt;
[[Disclaimer]]　[[Privacy Policy]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=UnixClassWiki:%E6%9C%80%E8%BF%91%E3%81%AE%E5%87%BA%E6%9D%A5%E4%BA%8B&amp;diff=1744</id>
		<title>UnixClassWiki:最近の出来事</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=UnixClassWiki:%E6%9C%80%E8%BF%91%E3%81%AE%E5%87%BA%E6%9D%A5%E4%BA%8B&amp;diff=1744"/>
		<updated>2024-07-25T21:09:57Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== おしらせ ==&lt;br /&gt;
&lt;br /&gt;
=== 大胆にMediawikiのバージョンをあげた ===&lt;br /&gt;
&lt;br /&gt;
そのため、あちこちのフォーマットがおかしい。チマチマとなおす予定 [[利用者:Hironobu|Hironobu]] ([[利用者・トーク:Hironobu|トーク]]) 2024年7月26日 (金) 06:09 (JST)&lt;br /&gt;
&lt;br /&gt;
=== サーバーをひっこした ===&lt;br /&gt;
&lt;br /&gt;
すこし上位の機種のサーバーをレンタルしたので、そこに引っ越した。&lt;br /&gt;
[[利用者:Hironobu|Hironobu]] ([[利用者・トーク:Hironobu|トーク]]) 2021年3月9日 (火) 17:28 (UTC)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== サーバーが新しくなった ===&lt;br /&gt;
&lt;br /&gt;
サーバをuc.h2np.netからuc2.h2np.netへ引っ越しました。そのタイミングでmediawikiのバージョンをあげ、さらにはタブレットやスマートフォン向けのスキンも入れました。旧サーバであるuc.h2np.netからリダイレクトするようにはしましたが、uc.h2np.netとuc2.h2np.netでは一部ディレクトリ構成が違うので、直接ファイルにリンクしている場合はエラーになる場合がありますので注意してください。--[[利用者:Hironobu|Hironobu]] ([[利用者・トーク:Hironobu|トーク]]) 2014年2月20日 (木) 02:48 (JST)&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E5%85%AC%E9%96%8B%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%90%84%E7%A8%AEUNIX%E9%96%A2%E9%80%A3%E6%9C%AC&amp;diff=1741</id>
		<title>公開されている各種UNIX関連本</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E5%85%AC%E9%96%8B%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%90%84%E7%A8%AEUNIX%E9%96%A2%E9%80%A3%E6%9C%AC&amp;diff=1741"/>
		<updated>2024-05-08T04:17:21Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* The Bash Guide */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= 公開されているUNIX関連の本 =&lt;br /&gt;
&lt;br /&gt;
== The Linux Command Line by William Shotts ==&lt;br /&gt;
&lt;br /&gt;
*  [https://linuxcommand.org/ The Linux Command Line by William Shotts]&lt;br /&gt;
&lt;br /&gt;
GNU/Linuxの端末上でシェルのインタフェースからコマンドを使う方法について説明。&lt;br /&gt;
&lt;br /&gt;
== Advanced Bash-Scripting Guide ==&lt;br /&gt;
&lt;br /&gt;
* [https://tldp.org/LDP/abs/html/ Advanced Bash-Scripting Guide]  An in-depth exploration of the art of shell scripting by Mendel Cooper&lt;br /&gt;
&lt;br /&gt;
Bashを使ってのシェルプログラミングについての詳しい説明。&lt;br /&gt;
&lt;br /&gt;
== The Bash Guide == &lt;br /&gt;
&lt;br /&gt;
*  [https://guide.bash.academy/ The Bash Guide]  A quality-driven guide through the shell&#039;s many features.&lt;br /&gt;
&lt;br /&gt;
Bashの利用方法に関する詳しい説明。&lt;br /&gt;
&lt;br /&gt;
== Linux Kernel in a Nutshell ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.kroah.com/lkn/ Linux Kernel in a Nutshell] by Greg Kroah-Hartman.&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E5%85%AC%E9%96%8B%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%90%84%E7%A8%AEUNIX%E9%96%A2%E9%80%A3%E6%9C%AC&amp;diff=1740</id>
		<title>公開されている各種UNIX関連本</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E5%85%AC%E9%96%8B%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%90%84%E7%A8%AEUNIX%E9%96%A2%E9%80%A3%E6%9C%AC&amp;diff=1740"/>
		<updated>2024-05-08T04:14:22Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: ページの作成:「= 公開されているUNIX関連の本 =  == The Linux Command Line by William Shotts ==  *  [https://linuxcommand.org/ The Linux Command Line by William Shotts]  GNU/Li...」&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= 公開されているUNIX関連の本 =&lt;br /&gt;
&lt;br /&gt;
== The Linux Command Line by William Shotts ==&lt;br /&gt;
&lt;br /&gt;
*  [https://linuxcommand.org/ The Linux Command Line by William Shotts]&lt;br /&gt;
&lt;br /&gt;
GNU/Linuxの端末上でシェルのインタフェースからコマンドを使う方法について説明。&lt;br /&gt;
&lt;br /&gt;
== Advanced Bash-Scripting Guide ==&lt;br /&gt;
&lt;br /&gt;
* [https://tldp.org/LDP/abs/html/ Advanced Bash-Scripting Guide]  An in-depth exploration of the art of shell scripting by Mendel Cooper&lt;br /&gt;
&lt;br /&gt;
Bashを使ってのシェルプログラミングについての詳しい説明。&lt;br /&gt;
&lt;br /&gt;
== The Bash Guide == &lt;br /&gt;
&lt;br /&gt;
*  [https://guide.bash.academy/ The Bash Guide]  A quality-driven guide through the shell&#039;s many features.&lt;br /&gt;
&lt;br /&gt;
Bashの利用方法に関する詳しい説明。&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=UNIX%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;diff=1739</id>
		<title>UNIXオペレーティングシステム</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=UNIX%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;diff=1739"/>
		<updated>2024-05-08T04:04:49Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 各種資料 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
このサイトはGNU/Linuxを通してUNIXオペレーティングシステムを学ぶ授業で使うテキストを掲載しています。詳しくは[[このサイトについて]]のページを参照ください。また何故GNU/Linuxを取り上げるのかは「[[なぜUNIXオペレーティングシステムの授業にGNU/Linuxを取り上げるのか]]」を参照してください。&lt;br /&gt;
&lt;br /&gt;
=== テキストの[[目次]] ===&lt;br /&gt;
&lt;br /&gt;
* 第一章 [[オペレーティングシステムとは何か]]&lt;br /&gt;
** 第一章:補遺:1 [[UNIXとは何か]]&lt;br /&gt;
** 第一章:補遺:2 [[OS誕生からLinuxまでの歴史]]&lt;br /&gt;
* 第二章  [[実際にGNU/Linuxを使ってみよう]]&lt;br /&gt;
** 第二章:補遺:2 [[Ubuntuインストール方法]]&lt;br /&gt;
** 第二章:補遺:3 [[Ubuntu Live CD]]&lt;br /&gt;
* 第三章 [[システム環境を考えてみる]]&lt;br /&gt;
* 第四章 [[カーネルの構造と機能]]&lt;br /&gt;
* 第五章 [[プロセス管理]]&lt;br /&gt;
** 第五章: 補遺:1 [[プロセスのタイムスライスの値を計測する]]&lt;br /&gt;
** 第五章: 補遺:2 [[マルチプロセッサとプロセス]]&lt;br /&gt;
* 第六章 [[記憶管理]]&lt;br /&gt;
** 第六章: 補遺:1 [[Linuxのswapについて私が知っている二、三の事柄]]&lt;br /&gt;
* 第七章 [[デバイススペシャルファイル]]&lt;br /&gt;
** 第七章: 補遺:1 [[Linux LVM]]&lt;br /&gt;
* 第八章 [[ファイルシステム]]&lt;br /&gt;
* 第九章 [[ユーザ権限とアクセス制御]]&lt;br /&gt;
** 第九章: 補遺:1 [[システムにおけるパスワード管理の概要]]&lt;br /&gt;
** 第九章: 補遺:2 [[パスワードファイル]]&lt;br /&gt;
* 第十章 [[プロセス間通信]]&lt;br /&gt;
* 第十一章 [[TCP/IP]]&lt;br /&gt;
** 第十一章:補遺:1 [[アプリケーションサーバ]]&lt;br /&gt;
&lt;br /&gt;
テキストの[[目次]]はこちらからも参照できます。&lt;br /&gt;
&lt;br /&gt;
=== QRコード ===&lt;br /&gt;
&lt;br /&gt;
このページへのQRコードです。&lt;br /&gt;
iPhone や Android からアクセスする際にお使いください。&lt;br /&gt;
&lt;br /&gt;
[[image:QRcode.png|150px]]&lt;br /&gt;
&lt;br /&gt;
=== 各種資料 ===&lt;br /&gt;
&lt;br /&gt;
* [[各種資料]]&lt;br /&gt;
* [[公開されている各種UNIX関連本]]&lt;br /&gt;
* [[NeXus2016カンファレンス]]&lt;br /&gt;
&lt;br /&gt;
=== 過去の資料 ===&lt;br /&gt;
&lt;br /&gt;
* [[2007年リチャードストールマン講演会]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
過去に掲示した内容等は[[過去掲示分]]からもたどれます。&lt;br /&gt;
&lt;br /&gt;
== その他 ==&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: http://uc2.h2np.net/i/a6.html&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
著者への [http://uc2.h2np.net/index.php/Contactpage コンタクト]&lt;br /&gt;
&lt;br /&gt;
[[Disclaimer]]　[[Privacy Policy]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1738</id>
		<title>ユーザ権限とアクセス制御</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1738"/>
		<updated>2024-02-01T14:18:05Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 実行権限を限定させる */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== ユーザと権限  ==&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステム内部ではユーザの違いをアカウント名ではなく&lt;br /&gt;
ユーザID(UID / User IDentifier)による数値で認識しています。&lt;br /&gt;
またユーザは1つデフォルトのグループID(GID / GroupIDentifier)がつけられています。&lt;br /&gt;
そのユーザIDやグループIDが条件に合致するかどうかでユーザに権限があるかどうかを判断しています。&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
RED HAT ENTERPRISE LINUX Identity Management ガイド&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/identity_management_guide/index&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: ユーザやグループの追加、更新などオペレーションに関しては[[ユーザやグループの管理]]を参照してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
唯一例外的なのはユーザIDが0、グループIDが0のユーザrootです。&lt;br /&gt;
スーパーユーザーと呼ばれ、&lt;br /&gt;
UNIXにおいてはオールマイティーな権限を持つ特別なユーザです。&lt;br /&gt;
管理者権限として説明される場合が多いのですが、&lt;br /&gt;
管理者として何かするという表現よりも「オペレーティングシステム上で何でもできてしまう権限」&lt;br /&gt;
と説明した方が分かり易いかと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ユーザIDとグループIDによるアクセス制御 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの内部では、ユーザは名前で管理されているのではなくユーザID(UID)で管理されています。&lt;br /&gt;
たとえばファイルにユーザ(所有者)が設定されていますが、その所有者情報とはファイルの情報（ディレクトリ情報のなかにあるメタ情報）に付加されているユーザIDのことです。&lt;br /&gt;
また、プロセスが動作している時には、いずれかのユーザIDとグループIDを持っており、そのユーザIDに付加された権限の範囲内においてプロセスは資源にアクセスできます。&lt;br /&gt;
グループID(GID)は、そのグループにユーザが登録されている場合、そのユーザに与えられるグループ権限です。&lt;br /&gt;
UNIXの基本的な権限は、このユーザIDの違いによるユーザ権限と、グループIDの違いによるグループ権限の2つから成り立っています。&lt;br /&gt;
ファイルやプロセスの資源へのアクセス制御はユーザID・グループID&lt;br /&gt;
&amp;lt;ref&amp;gt;自分のユーザIDやグループIDを確認するにはコマンドidを使う。詳しくは[[ユーザやグループの管理]]を参照のこと。&amp;lt;/ref&amp;gt;&lt;br /&gt;
を使っての許可・不許可によって行われるというのが基本的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずファイルに対するユーザIDとグループIDを見てみましょう。&lt;br /&gt;
ファイルには、ユーザIDとグループIDが設定されています。&lt;br /&gt;
ユーザID＝このファイルの所有者です。&lt;br /&gt;
尚、本章の範囲では、所有者とユーザと同じ意味で使っています。&lt;br /&gt;
ユーザが自分の所有するファイルの属性を変更し、そのファイルのアクセス権限などをコントロールすることができます。&lt;br /&gt;
ただしroot権限だけは例外で、システムのすべてに無制限にアクセスできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ユーザIDが数字ではなくユーザ名として表示されるのは、ユーザIDは/etc/passwdで設定されている対応するアカウント名、&lt;br /&gt;
グループIDは/etc/groupで設定されている対応するグループ名に変換されて表示されるからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 読み込み / 書き込み  / 実行 ===&lt;br /&gt;
&lt;br /&gt;
基本的なファイルへのアクセス権限は、「読み込み」「書き込み」「実行」です。&lt;br /&gt;
ディレクトリの場合は実行の部分の意味が「ディレクトリとしてアクセスできるか」ということとして扱われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*  アクセス権限 : 読み込み / 書き込み / 実行&lt;br /&gt;
*  ユーザ・所有者(User)に対して : 許可 / 不許可&lt;br /&gt;
*  グループ(Group)に対して : 許可 / 不許可&lt;br /&gt;
*  それ以外(Other)対して : 許可 / 不許可&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-r--r--    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
 $  ls -l /var/mail/hironobu&lt;br /&gt;
 -rw-rw----    1 hironobu mail            0 Dec  9 19:39 hironobu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
memo.txtはユーザIDがhironobu、グループIDがhironobuになっており、ユーザ（所有者）は読み書き、同じグループには読み込み、その他の権限でも読み込みができます。&lt;br /&gt;
正確には、ユーザと同じユーザIDを持ったプロセス、設定されたグループと同じグループに属するユーザIDを持つプロセス、それ以外のユーザIDを持つプロセスがアクセス可能であるという表現になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/var/mail/hironobuというファイルのユーザIDはhironobuになっており、グループIDはmailです。mailのグループ権限を持つプロセスから読み書き可能になっています。具体的には、メールサーバなどのプロセスが読み書きできるようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
変更はコマンドchmodを使います。chmodのオプションではユーザ（所有者）はu、グループはg、それ以外の利用者はoという表現を使います。&lt;br /&gt;
パーミッションの許可は&amp;quot;+&amp;quot;、パーミッションの不許可は&amp;quot;-&amp;quot;を使います。&lt;br /&gt;
chmodのオプションで&amp;quot;go-rw&amp;quot;はグループとその他ユーザからの読み書きは不許可となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ユーザ（所有者）、グループ、その他ユーザの読み取り許可・不許可、書き込み許可・不許可、実行の許可・不許可は3ビットで表すので、この部分を8進数で表現することもできます。&lt;br /&gt;
その場合&amp;quot;rw-------&amp;quot;はビットの設定がuが110、gが000、oが000となるので、8進数表現をするモードでは600となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 600 memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== グループID利用の方法 == &lt;br /&gt;
&lt;br /&gt;
ここにファイルgroup_share.datがあるとします。これをユーザtaroとユーザhanakoが共通に読み書きのアクセスでき、&lt;br /&gt;
他のユーザはアクセスできないようなパーミッションにしたいとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-r--r--  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずgroup_share.datを所有者とグループにはrw、それ以外には読み書き禁止にします。&lt;br /&gt;
chmodを使いますが、2度に分けてオプションを使ってもいいですし、モードを数字で与えてもかまいません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod o-wr group_share.dat &lt;br /&gt;
 $ chmod g+wr group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
あるいは&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 660 group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
結果は次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-rw----  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次にroot権限でtaroとhanakoの共通に使えるグループtaro-hanakoを作ります。&lt;br /&gt;
そしてtaro とhanakoをグループtaro-hanakoに加えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 # groupadd taro-hanako&lt;br /&gt;
 # gpasswd -a taro   taro-hanako&lt;br /&gt;
 # gpasswd -a hanako taro-hanako&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
taroが新しいグループに加わった時、taroが再度ログインした時からその新しいグループ (この場合taro-hanako)が有効になります。&lt;br /&gt;
再度ログインした状態で、taroはgroup_share.datのグループIDをtaro-hanakoにします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chgrp taro-hanako group_share.dat&lt;br /&gt;
 ...&lt;br /&gt;
 -rw-rw----  1 taro taro-hanako     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これでgroup_share.datはtaro-hanakoのグループに属しているtaroとhanakoが読み書きが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;考えてみよう: apacheはユーザwww-dataの権限で動作しています。cgi-binなどでコマンドを動かしファイルinfo.datに情報を書き込む必要があります。しかし、info.dataの中身に関してはセキュリティ上の問題のためユーザfoo以外には読ませたくありません(www-dataにも許可しません)。さて、この場合、info.datの適切なファイルの所有者、適切なパーミッションはどのようなものでしょうか。&lt;br /&gt;
&lt;br /&gt;
== プロセスのユーザIDとグループID ==&lt;br /&gt;
&lt;br /&gt;
まずログインした時に、そのアカウント名に割り振られたユーザIDとグループIDの権限でログインシェルが動き始めます。&lt;br /&gt;
そのシェルから起動されるプロセスにはデフォルトで親プロセスのユーザIDとグループIDが受け継がれます。&lt;br /&gt;
root権限(注)でsetuid(2)やsetgid(2)を使うとプロセスのユーザIDを変更することができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: setuid(2)やsetgid(2)の利用にはもう少し限定した条件があるので調べてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps aux&lt;br /&gt;
 USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND&lt;br /&gt;
 root         1  0.0  0.0  1272  432 ?        S    Aug23   1:49 init [2]       &lt;br /&gt;
 ...&lt;br /&gt;
 daemon     126  0.0  0.0  1384  296 ?        S    Aug23   0:00 /sbin/portmap&lt;br /&gt;
 canna     2799  0.0  2.7 19152 17568 ?       S    Aug23  13:02 /usr/sbin/cannase&lt;br /&gt;
 root     23439  0.0  0.1  2936  660 ?        S    Nov24   0:17 /usr/sbin/apache&lt;br /&gt;
 www-data 23474  0.0  0.0  2948  632 ?        S    Nov24   0:00 /usr/sbin/apache&lt;br /&gt;
 hironobu 20287  0.0  0.0  2464  224 pts/0    S    Oct16   0:00 bash&lt;br /&gt;
 hironobu  2796  0.0  1.0  8752 6716 ?        R    12:14   0:05 emacs20 -geometry&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 現在の権限管理 === &lt;br /&gt;
&lt;br /&gt;
古典的なUNIXはUIDとGIDだけで説明は済みますが、Linuxも含めBSD 4.3以降では、もっと複雑な設定ができます。&lt;br /&gt;
Linuxでは4つタイプのUIDと4つのGIDのタイプを持っています。&lt;br /&gt;
&lt;br /&gt;
*  ユーザID、グループIDの種類&lt;br /&gt;
* UID / GID : 今まで通りのUID / GID &lt;br /&gt;
* RUID / RGID : 実UID / 実GID --- UIDやGIDと同じ役割 (RはReal)&lt;br /&gt;
* EUID / EGID : 実効UID / 実効GID --- 権限があるかどうかをチェックする時に使う (EはEffective)&lt;br /&gt;
* SUID / SGID : 保存UID / 保存GID --- 有効化・無効化を行うための保存 (SはSaved)&lt;br /&gt;
* FSUID / FSGID : ファイルUID / ファイルGID --- Linux独自のファイルのアクセス権限のチェック&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== setuid  === &lt;br /&gt;
&lt;br /&gt;
これらはプロセスが、どのような権限で動作するかを規定するものです。&lt;br /&gt;
UNIXには実行ファイルの属性に(モードに)setuid bitを設定しておくと、&lt;br /&gt;
その実行ファイルはファイルの所有者の権限で動作します。&lt;br /&gt;
setgid bitは実行ファイルのグループの権限で動作します。&lt;br /&gt;
コマンドfindを使って探してみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +a+s -exec ls -l {} \;&lt;br /&gt;
 -rwsr-xr-x 1 root root 26252 Mar  3  2012 /bin/fusermount&lt;br /&gt;
 -rwsr-xr-x 1 root root 88760 Mar 30  2012 /bin/mount&lt;br /&gt;
 -rwsr-xr-x 1 root root 34740 Nov  8  2011 /bin/ping&lt;br /&gt;
 -rwsr-xr-x 1 root root 39116 Nov  8  2011 /bin/ping6&lt;br /&gt;
 -rwsr-xr-x 1 root root 31116 Sep 13  2012 /bin/su&lt;br /&gt;
 -rwsr-xr-x 1 root root 67720 Mar 30  2012 /bin/umount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初の表示にある-rwsr-x-rxのsがsetuid bitの意味です。&lt;br /&gt;
つまり、これらのコマンドは所有者がrootであり、かつ、&lt;br /&gt;
このコマンドを動かすとrootの権限で動かすことができるという意味です。&lt;br /&gt;
この実行時は、ruidは利用者、euidがrootとなり、&lt;br /&gt;
root権限のファイルなどに書き込むことができるようになります。&lt;br /&gt;
一般ユーザでも何でもできる権限を手に入れてしまうということで、&lt;br /&gt;
このようなプログラムに誤りがあると大きなセキュリティ上の問題になります。&lt;br /&gt;
&lt;br /&gt;
=== setgid === &lt;br /&gt;
&lt;br /&gt;
setgidは、set group id bitの意味です。そのファイルのグループIDと同じ権限で実行できます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +g+s -exec ls -l {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 実行権限を限定させる ===&lt;br /&gt;
&lt;br /&gt;
ruidがrootの時、つまりrootがファイルを実行した時は何でもできるので、euidをプロセス内で制限なく変更できます。&lt;br /&gt;
たとえばapacheは唯一1つrootでのプロセスがあり、&lt;br /&gt;
そこから生成し子プロセスがwww-data（あるいは他の）euidで動作します。&lt;br /&gt;
外部からのアクセスはすべてwww-dataのeuidで動いている子プロセスで動作しているので、&lt;br /&gt;
万が一、外部からの入力によりapache誤った動作をしても、&lt;br /&gt;
その影響範囲を無制限にはしない（root権限ではない）ようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RUID/RGID、EUID/EGID、SUID/SGIDを上手に変更することによって、どのユーザ権限で、&lt;br /&gt;
あるいはどのグループ権限でプロセスを動かし、適切にファイルや資源にアクセスできるようになることで、&lt;br /&gt;
セキュリティを保つことができるようになります。&lt;br /&gt;
これらの値のセットにはルールがあるので、全部はかけないですが、典型的なものを書き出してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* RUID / EUID / SUIDの設定ルール&lt;br /&gt;
*  RUID の値を  EUID にセットできる&lt;br /&gt;
* EUID の値を  RUID にセットできる&lt;br /&gt;
* 実行時のEUIDがSUIDにコピーされていて、SUIDの値をEUIDにセットできる&lt;br /&gt;
* rootはRUIDもEUIDも自由にセットできる&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように実行時のユーザIDを変えることができ、また一般ユーザでも実行ファイルに権限が附加されていれば、&lt;br /&gt;
root権限でプロセスを動かすこともできるなどかなり複雑な権限のコントロールが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もちろん、Linuxがコントロールが可能であることと、&lt;br /&gt;
アプリケーションがきちんと矛盾なく利用できるように設計できることとはまったく別のことです。&lt;br /&gt;
アプリケーションの設計が正しくなかったり、実装で間違えていると、セキュリティ侵害が発生する&amp;lt;ref&amp;gt;POS37-C. 権限の破棄は確実に行う 【[https://www.jpcert.or.jp/sc-rules/c-pos37-c.html JPCERT/CCサイトへ]】&amp;lt;/ref&amp;gt;ことはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
=== なるべくrootでは動かさない運用 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まだセキュリティなどをあまり気にせず、サーバとして動作しているものは何でもかんでもrootで実行していた時期がUNIXにもありました。&lt;br /&gt;
これの利点は、アクセスする先のファイルのパーミッションやroot権限でしかオープンできないポート番号など一々気にしなくてもかまわないという点です。&lt;br /&gt;
しかし、万が一、このサーバプロセスが何かの形で乗っ取られてしまい侵入者が外部から任意のコマンドを動かすことが出来るなら、侵入者にシステムに対して万能の権限を持ってしまうことになります。&lt;br /&gt;
現在では実行権限はなるべく絞る形で運用されています。&lt;br /&gt;
たとえばhttpd(apache)は1つだけrootで稼働しポートのオープンや子プロセスを生成するといった処理をします。&lt;br /&gt;
実際のHTTPリクエストに対する対応は別の権限を与えて実行しています。たとえば下の例だとapache/apacheの権限でプロセスを動作させています。&lt;br /&gt;
万が一、外部から不当なコマンドが動かされる事態になっても、apacheのユーザ権限が及ぶ範囲でしか被害がありません。&lt;br /&gt;
システムの書き換えなど重大なセキュリティ侵害からシステムを守り被害を最小限にできるようなシステムの設計にするのが現在の一般的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
% ps -eo user,group,args | grep httpd&lt;br /&gt;
root     root     /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ディレクトリへの特殊な設定 ==&lt;br /&gt;
=== ディレクトリにsetgidビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ディレクトリのグループにsetgidビットを設定すると、そのディレクトリ以下に作られるファイル及びディレクトリには現ディレクトリのグループが適用されます。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ls -l&lt;br /&gt;
合計 4&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:35 foo&lt;br /&gt;
$ sudo touch foo/fileA&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:36 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
この例は、fooというディレクトリがあり、そのディレクトリ下にコマンド touch を使いrootの持ち物である fileA を作成します。&lt;br /&gt;
この時のfileAの所有者、グループともrootです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ chmod g+s foo&lt;br /&gt;
$ ls -ld foo&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:36 foo&lt;br /&gt;
$ sudo touch foo/fileB&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:37 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
-rw-r----- 1 root     hironobu    0 12月 14 02:37 fileB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ディレクトリ foo に対しsetgid ビットの設定を行います。setgid ビットがセットされるとグループの&amp;quot;x&amp;quot;だった部分が&amp;quot;s&amp;quot;に変化します。&lt;br /&gt;
次にコマンド touch で fileB を作成します。 &lt;br /&gt;
ディレクトリのグループ hironobu がファイルに継承されて fileB の所有者は root グループが hironobu になります。&lt;br /&gt;
&lt;br /&gt;
=== ディレクトリにStickyビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ユーザ(user)が読み書きできるディレクトリにStickyビットを設定した場合、そのディレクトリにどのユーザでもファイルを作成することができますが、ディレクトリから削除する場合、そのファイルの所有者(owner)しか削除できません。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ mkdir temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxr----- 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
$ chmod go+rwxt temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxrwxrwt 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ACL ==&lt;br /&gt;
&lt;br /&gt;
Access Control Lists（ACL）は元々のUNIXにはないアクセス制御方式で、その仕様に関してはPOSIXで定義されています。Linuxカーネル2.6以降で採用されています。Linuxカーネル2.6以降ではLinuxの主要ファイルシステムで利用可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXでは自分以外のユーザにアクセスを許可する場合は、グループに許可するか、それともすべてのユーザに許可するかの大まかな条件でアクセス制御をしています。一方、ACLではアクセス許可を特定のユーザの単位で、あるいはグループ単位で設定できます。ACLの導入により、これまでのUNIXのアクセス制御よりも限定的な設定をすることが可能になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次のようなファイルがあるとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $touch foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw-rw-r-- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コマンドgetfaclを使ってパーミッションを表示すると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt &lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 group::rw-&lt;br /&gt;
 other::r--&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次に自分以外のユーザが読み書きできないようにしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw------- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この状態でwww-dataユーザのみにfoo.txtの読み込みを許諾するとなると、グループを使う方法だとwww-dataとhironobuだけのグループを作り、そのグループを設定し、グループの読み込みを許可する、といったことをしなければなりません。このWebサーバがアクセスしなければならないファイルの所有者がhironobuのユーザしか存在していないのならば、グループで運用するのも問題ありません。しかし、もし、hironobu以外にmasamiというユーザがいたならば、双方別々のグループを作りwww-dataを加えるといった方法が必要になります。もちろんこの方法はユーザが増えるたびにグループも増えます。&lt;br /&gt;
&lt;br /&gt;
そこでACLの登場です。www-dataのアカウントのみを直接指定してアクセスを許すといった個別の対応ができれば、これまでのUNIXのアクセス権限の手法よりもシンプルに扱うことが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
=== ACLの設定 ===&lt;br /&gt;
&lt;br /&gt;
コマンドsetfaclはaclをセットするためのものです。ユーザwww-dataに&amp;quot;r&amp;quot;だけ許可をしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ setfacl -m user:www-data:r foo.txt &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ではコマンドgetfaclを使って、どう変化したか見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt&lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 user:www-data:r--&lt;br /&gt;
 group::---&lt;br /&gt;
 mask::r--&lt;br /&gt;
 other::---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
先ほどの内容から2点変わっているのがわかるはずです。まず1点はuserの表示が増えたこと、そしてmaskという新しい項目ができたことです。maskは所有するユーザ以外に与えることのできる最大限の権限です。この場合はmaskに対して指定していないのでデフォルトの&amp;quot;r&amp;quot;が設定されています。&lt;br /&gt;
ここではwww-dataのみですが、複数のユーザに対しても同様に個別の設定をすることができます。&lt;br /&gt;
ここではユーザのみに関して説明していますが、グループに対しても複数のグループを割り当てたりすることが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さらに詳しく知るためには&lt;br /&gt;
openSUSE&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 20 Linux でのアクセス制御リスト&lt;br /&gt;
https://www.belbel.or.jp/opensuse-manuals_ja/cha-security-acls.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
やRadHat&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
システム管理者のガイド 第5章 アクセス制御リスト&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-access_control_lists&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
などのACLに関する運用ドキュメントが参考になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、この状態でls -lでファイルのパーミッションの状況をみてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % ls -l foo.txt&lt;br /&gt;
 -rw-r-----+ 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最後に&amp;quot;+&amp;quot;と表示されているのは、ACLが設定されているということを意味しています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/df.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1737</id>
		<title>ユーザ権限とアクセス制御</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1737"/>
		<updated>2024-02-01T14:17:05Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* setgid */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== ユーザと権限  ==&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステム内部ではユーザの違いをアカウント名ではなく&lt;br /&gt;
ユーザID(UID / User IDentifier)による数値で認識しています。&lt;br /&gt;
またユーザは1つデフォルトのグループID(GID / GroupIDentifier)がつけられています。&lt;br /&gt;
そのユーザIDやグループIDが条件に合致するかどうかでユーザに権限があるかどうかを判断しています。&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
RED HAT ENTERPRISE LINUX Identity Management ガイド&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/identity_management_guide/index&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: ユーザやグループの追加、更新などオペレーションに関しては[[ユーザやグループの管理]]を参照してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
唯一例外的なのはユーザIDが0、グループIDが0のユーザrootです。&lt;br /&gt;
スーパーユーザーと呼ばれ、&lt;br /&gt;
UNIXにおいてはオールマイティーな権限を持つ特別なユーザです。&lt;br /&gt;
管理者権限として説明される場合が多いのですが、&lt;br /&gt;
管理者として何かするという表現よりも「オペレーティングシステム上で何でもできてしまう権限」&lt;br /&gt;
と説明した方が分かり易いかと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ユーザIDとグループIDによるアクセス制御 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの内部では、ユーザは名前で管理されているのではなくユーザID(UID)で管理されています。&lt;br /&gt;
たとえばファイルにユーザ(所有者)が設定されていますが、その所有者情報とはファイルの情報（ディレクトリ情報のなかにあるメタ情報）に付加されているユーザIDのことです。&lt;br /&gt;
また、プロセスが動作している時には、いずれかのユーザIDとグループIDを持っており、そのユーザIDに付加された権限の範囲内においてプロセスは資源にアクセスできます。&lt;br /&gt;
グループID(GID)は、そのグループにユーザが登録されている場合、そのユーザに与えられるグループ権限です。&lt;br /&gt;
UNIXの基本的な権限は、このユーザIDの違いによるユーザ権限と、グループIDの違いによるグループ権限の2つから成り立っています。&lt;br /&gt;
ファイルやプロセスの資源へのアクセス制御はユーザID・グループID&lt;br /&gt;
&amp;lt;ref&amp;gt;自分のユーザIDやグループIDを確認するにはコマンドidを使う。詳しくは[[ユーザやグループの管理]]を参照のこと。&amp;lt;/ref&amp;gt;&lt;br /&gt;
を使っての許可・不許可によって行われるというのが基本的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずファイルに対するユーザIDとグループIDを見てみましょう。&lt;br /&gt;
ファイルには、ユーザIDとグループIDが設定されています。&lt;br /&gt;
ユーザID＝このファイルの所有者です。&lt;br /&gt;
尚、本章の範囲では、所有者とユーザと同じ意味で使っています。&lt;br /&gt;
ユーザが自分の所有するファイルの属性を変更し、そのファイルのアクセス権限などをコントロールすることができます。&lt;br /&gt;
ただしroot権限だけは例外で、システムのすべてに無制限にアクセスできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ユーザIDが数字ではなくユーザ名として表示されるのは、ユーザIDは/etc/passwdで設定されている対応するアカウント名、&lt;br /&gt;
グループIDは/etc/groupで設定されている対応するグループ名に変換されて表示されるからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 読み込み / 書き込み  / 実行 ===&lt;br /&gt;
&lt;br /&gt;
基本的なファイルへのアクセス権限は、「読み込み」「書き込み」「実行」です。&lt;br /&gt;
ディレクトリの場合は実行の部分の意味が「ディレクトリとしてアクセスできるか」ということとして扱われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*  アクセス権限 : 読み込み / 書き込み / 実行&lt;br /&gt;
*  ユーザ・所有者(User)に対して : 許可 / 不許可&lt;br /&gt;
*  グループ(Group)に対して : 許可 / 不許可&lt;br /&gt;
*  それ以外(Other)対して : 許可 / 不許可&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-r--r--    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
 $  ls -l /var/mail/hironobu&lt;br /&gt;
 -rw-rw----    1 hironobu mail            0 Dec  9 19:39 hironobu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
memo.txtはユーザIDがhironobu、グループIDがhironobuになっており、ユーザ（所有者）は読み書き、同じグループには読み込み、その他の権限でも読み込みができます。&lt;br /&gt;
正確には、ユーザと同じユーザIDを持ったプロセス、設定されたグループと同じグループに属するユーザIDを持つプロセス、それ以外のユーザIDを持つプロセスがアクセス可能であるという表現になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/var/mail/hironobuというファイルのユーザIDはhironobuになっており、グループIDはmailです。mailのグループ権限を持つプロセスから読み書き可能になっています。具体的には、メールサーバなどのプロセスが読み書きできるようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
変更はコマンドchmodを使います。chmodのオプションではユーザ（所有者）はu、グループはg、それ以外の利用者はoという表現を使います。&lt;br /&gt;
パーミッションの許可は&amp;quot;+&amp;quot;、パーミッションの不許可は&amp;quot;-&amp;quot;を使います。&lt;br /&gt;
chmodのオプションで&amp;quot;go-rw&amp;quot;はグループとその他ユーザからの読み書きは不許可となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ユーザ（所有者）、グループ、その他ユーザの読み取り許可・不許可、書き込み許可・不許可、実行の許可・不許可は3ビットで表すので、この部分を8進数で表現することもできます。&lt;br /&gt;
その場合&amp;quot;rw-------&amp;quot;はビットの設定がuが110、gが000、oが000となるので、8進数表現をするモードでは600となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 600 memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== グループID利用の方法 == &lt;br /&gt;
&lt;br /&gt;
ここにファイルgroup_share.datがあるとします。これをユーザtaroとユーザhanakoが共通に読み書きのアクセスでき、&lt;br /&gt;
他のユーザはアクセスできないようなパーミッションにしたいとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-r--r--  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずgroup_share.datを所有者とグループにはrw、それ以外には読み書き禁止にします。&lt;br /&gt;
chmodを使いますが、2度に分けてオプションを使ってもいいですし、モードを数字で与えてもかまいません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod o-wr group_share.dat &lt;br /&gt;
 $ chmod g+wr group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
あるいは&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 660 group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
結果は次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-rw----  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次にroot権限でtaroとhanakoの共通に使えるグループtaro-hanakoを作ります。&lt;br /&gt;
そしてtaro とhanakoをグループtaro-hanakoに加えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 # groupadd taro-hanako&lt;br /&gt;
 # gpasswd -a taro   taro-hanako&lt;br /&gt;
 # gpasswd -a hanako taro-hanako&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
taroが新しいグループに加わった時、taroが再度ログインした時からその新しいグループ (この場合taro-hanako)が有効になります。&lt;br /&gt;
再度ログインした状態で、taroはgroup_share.datのグループIDをtaro-hanakoにします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chgrp taro-hanako group_share.dat&lt;br /&gt;
 ...&lt;br /&gt;
 -rw-rw----  1 taro taro-hanako     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これでgroup_share.datはtaro-hanakoのグループに属しているtaroとhanakoが読み書きが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;考えてみよう: apacheはユーザwww-dataの権限で動作しています。cgi-binなどでコマンドを動かしファイルinfo.datに情報を書き込む必要があります。しかし、info.dataの中身に関してはセキュリティ上の問題のためユーザfoo以外には読ませたくありません(www-dataにも許可しません)。さて、この場合、info.datの適切なファイルの所有者、適切なパーミッションはどのようなものでしょうか。&lt;br /&gt;
&lt;br /&gt;
== プロセスのユーザIDとグループID ==&lt;br /&gt;
&lt;br /&gt;
まずログインした時に、そのアカウント名に割り振られたユーザIDとグループIDの権限でログインシェルが動き始めます。&lt;br /&gt;
そのシェルから起動されるプロセスにはデフォルトで親プロセスのユーザIDとグループIDが受け継がれます。&lt;br /&gt;
root権限(注)でsetuid(2)やsetgid(2)を使うとプロセスのユーザIDを変更することができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: setuid(2)やsetgid(2)の利用にはもう少し限定した条件があるので調べてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps aux&lt;br /&gt;
 USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND&lt;br /&gt;
 root         1  0.0  0.0  1272  432 ?        S    Aug23   1:49 init [2]       &lt;br /&gt;
 ...&lt;br /&gt;
 daemon     126  0.0  0.0  1384  296 ?        S    Aug23   0:00 /sbin/portmap&lt;br /&gt;
 canna     2799  0.0  2.7 19152 17568 ?       S    Aug23  13:02 /usr/sbin/cannase&lt;br /&gt;
 root     23439  0.0  0.1  2936  660 ?        S    Nov24   0:17 /usr/sbin/apache&lt;br /&gt;
 www-data 23474  0.0  0.0  2948  632 ?        S    Nov24   0:00 /usr/sbin/apache&lt;br /&gt;
 hironobu 20287  0.0  0.0  2464  224 pts/0    S    Oct16   0:00 bash&lt;br /&gt;
 hironobu  2796  0.0  1.0  8752 6716 ?        R    12:14   0:05 emacs20 -geometry&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 現在の権限管理 === &lt;br /&gt;
&lt;br /&gt;
古典的なUNIXはUIDとGIDだけで説明は済みますが、Linuxも含めBSD 4.3以降では、もっと複雑な設定ができます。&lt;br /&gt;
Linuxでは4つタイプのUIDと4つのGIDのタイプを持っています。&lt;br /&gt;
&lt;br /&gt;
*  ユーザID、グループIDの種類&lt;br /&gt;
* UID / GID : 今まで通りのUID / GID &lt;br /&gt;
* RUID / RGID : 実UID / 実GID --- UIDやGIDと同じ役割 (RはReal)&lt;br /&gt;
* EUID / EGID : 実効UID / 実効GID --- 権限があるかどうかをチェックする時に使う (EはEffective)&lt;br /&gt;
* SUID / SGID : 保存UID / 保存GID --- 有効化・無効化を行うための保存 (SはSaved)&lt;br /&gt;
* FSUID / FSGID : ファイルUID / ファイルGID --- Linux独自のファイルのアクセス権限のチェック&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== setuid  === &lt;br /&gt;
&lt;br /&gt;
これらはプロセスが、どのような権限で動作するかを規定するものです。&lt;br /&gt;
UNIXには実行ファイルの属性に(モードに)setuid bitを設定しておくと、&lt;br /&gt;
その実行ファイルはファイルの所有者の権限で動作します。&lt;br /&gt;
setgid bitは実行ファイルのグループの権限で動作します。&lt;br /&gt;
コマンドfindを使って探してみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +a+s -exec ls -l {} \;&lt;br /&gt;
 -rwsr-xr-x 1 root root 26252 Mar  3  2012 /bin/fusermount&lt;br /&gt;
 -rwsr-xr-x 1 root root 88760 Mar 30  2012 /bin/mount&lt;br /&gt;
 -rwsr-xr-x 1 root root 34740 Nov  8  2011 /bin/ping&lt;br /&gt;
 -rwsr-xr-x 1 root root 39116 Nov  8  2011 /bin/ping6&lt;br /&gt;
 -rwsr-xr-x 1 root root 31116 Sep 13  2012 /bin/su&lt;br /&gt;
 -rwsr-xr-x 1 root root 67720 Mar 30  2012 /bin/umount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初の表示にある-rwsr-x-rxのsがsetuid bitの意味です。&lt;br /&gt;
つまり、これらのコマンドは所有者がrootであり、かつ、&lt;br /&gt;
このコマンドを動かすとrootの権限で動かすことができるという意味です。&lt;br /&gt;
この実行時は、ruidは利用者、euidがrootとなり、&lt;br /&gt;
root権限のファイルなどに書き込むことができるようになります。&lt;br /&gt;
一般ユーザでも何でもできる権限を手に入れてしまうということで、&lt;br /&gt;
このようなプログラムに誤りがあると大きなセキュリティ上の問題になります。&lt;br /&gt;
&lt;br /&gt;
=== setgid === &lt;br /&gt;
&lt;br /&gt;
setgidは、set group id bitの意味です。そのファイルのグループIDと同じ権限で実行できます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +g+s -exec ls -l {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 実行権限を限定させる ===&lt;br /&gt;
&lt;br /&gt;
ruidがrootの時、つまりrootがファイルを実行した時は何でもできるので、euidをプロセス内で制限なく変更できます。&lt;br /&gt;
たとえばapacheは唯一1つrootでのプロセスがあり、&lt;br /&gt;
そこから生成し子プロセスがwww-data（あるいは他の）euidで動作します。&lt;br /&gt;
外部からのアクセスはすべてwww-dataのeuidで動いている子プロセスで動作しているので、&lt;br /&gt;
万が一、外部からの入力によりapache誤った動作をしても、&lt;br /&gt;
その影響範囲を無制限にはしない（root権限ではない）ようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RUID/RGID、EUID/EGID、SUID/SGIDを上手に変更することによって、どのユーザ権限で、&lt;br /&gt;
あるいはどのグループ権限でプロセスを動かし、適切にファイルや資源にアクセスできるようになることで、&lt;br /&gt;
セキュリティを保つことができるようになります。&lt;br /&gt;
これらの値のセットにはルールがあるので、全部はかけないですが、典型的なものを書き出してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* RUID / EUID / SUIDの設定ルール&lt;br /&gt;
*  RUID の値を  EUID にセットできる&lt;br /&gt;
* EUID の値を  RUID にセットできる&lt;br /&gt;
* 実行時のEUIDがSUIDにコピーされていて、SUIDの値をEUIDにセットできる&lt;br /&gt;
* rootはRUIDもEUIDも自由にセットできる&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように実行時のユーザIDを変えることができ、また一般ユーザでも実行ファイルに権限が附加されていれば、&lt;br /&gt;
root権限でプロセスを動かすこともできるなどかなり複雑な権限のコントロールが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もちろん、Linuxがコントロールが可能であることと、&lt;br /&gt;
アプリケーションがきちんと矛盾なく利用できるように設計できることとはまったく別のことです。&lt;br /&gt;
アプリケーションの設計が正しくなかったり、実装で間違えていると、セキュリティ侵害が発生する&amp;lt;ref&amp;gt;POS37-C. 権限の破棄は確実に行う 【[https://www.jpcert.or.jp/sc-rules/c-pos37-c.html JPCERT/CC]】&amp;lt;/ref&amp;gt;ことはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
=== なるべくrootでは動かさない運用 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まだセキュリティなどをあまり気にせず、サーバとして動作しているものは何でもかんでもrootで実行していた時期がUNIXにもありました。&lt;br /&gt;
これの利点は、アクセスする先のファイルのパーミッションやroot権限でしかオープンできないポート番号など一々気にしなくてもかまわないという点です。&lt;br /&gt;
しかし、万が一、このサーバプロセスが何かの形で乗っ取られてしまい侵入者が外部から任意のコマンドを動かすことが出来るなら、侵入者にシステムに対して万能の権限を持ってしまうことになります。&lt;br /&gt;
現在では実行権限はなるべく絞る形で運用されています。&lt;br /&gt;
たとえばhttpd(apache)は1つだけrootで稼働しポートのオープンや子プロセスを生成するといった処理をします。&lt;br /&gt;
実際のHTTPリクエストに対する対応は別の権限を与えて実行しています。たとえば下の例だとapache/apacheの権限でプロセスを動作させています。&lt;br /&gt;
万が一、外部から不当なコマンドが動かされる事態になっても、apacheのユーザ権限が及ぶ範囲でしか被害がありません。&lt;br /&gt;
システムの書き換えなど重大なセキュリティ侵害からシステムを守り被害を最小限にできるようなシステムの設計にするのが現在の一般的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
% ps -eo user,group,args | grep httpd&lt;br /&gt;
root     root     /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ディレクトリへの特殊な設定 ==&lt;br /&gt;
=== ディレクトリにsetgidビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ディレクトリのグループにsetgidビットを設定すると、そのディレクトリ以下に作られるファイル及びディレクトリには現ディレクトリのグループが適用されます。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ls -l&lt;br /&gt;
合計 4&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:35 foo&lt;br /&gt;
$ sudo touch foo/fileA&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:36 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
この例は、fooというディレクトリがあり、そのディレクトリ下にコマンド touch を使いrootの持ち物である fileA を作成します。&lt;br /&gt;
この時のfileAの所有者、グループともrootです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ chmod g+s foo&lt;br /&gt;
$ ls -ld foo&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:36 foo&lt;br /&gt;
$ sudo touch foo/fileB&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:37 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
-rw-r----- 1 root     hironobu    0 12月 14 02:37 fileB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ディレクトリ foo に対しsetgid ビットの設定を行います。setgid ビットがセットされるとグループの&amp;quot;x&amp;quot;だった部分が&amp;quot;s&amp;quot;に変化します。&lt;br /&gt;
次にコマンド touch で fileB を作成します。 &lt;br /&gt;
ディレクトリのグループ hironobu がファイルに継承されて fileB の所有者は root グループが hironobu になります。&lt;br /&gt;
&lt;br /&gt;
=== ディレクトリにStickyビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ユーザ(user)が読み書きできるディレクトリにStickyビットを設定した場合、そのディレクトリにどのユーザでもファイルを作成することができますが、ディレクトリから削除する場合、そのファイルの所有者(owner)しか削除できません。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ mkdir temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxr----- 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
$ chmod go+rwxt temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxrwxrwt 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ACL ==&lt;br /&gt;
&lt;br /&gt;
Access Control Lists（ACL）は元々のUNIXにはないアクセス制御方式で、その仕様に関してはPOSIXで定義されています。Linuxカーネル2.6以降で採用されています。Linuxカーネル2.6以降ではLinuxの主要ファイルシステムで利用可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXでは自分以外のユーザにアクセスを許可する場合は、グループに許可するか、それともすべてのユーザに許可するかの大まかな条件でアクセス制御をしています。一方、ACLではアクセス許可を特定のユーザの単位で、あるいはグループ単位で設定できます。ACLの導入により、これまでのUNIXのアクセス制御よりも限定的な設定をすることが可能になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次のようなファイルがあるとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $touch foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw-rw-r-- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コマンドgetfaclを使ってパーミッションを表示すると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt &lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 group::rw-&lt;br /&gt;
 other::r--&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次に自分以外のユーザが読み書きできないようにしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw------- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この状態でwww-dataユーザのみにfoo.txtの読み込みを許諾するとなると、グループを使う方法だとwww-dataとhironobuだけのグループを作り、そのグループを設定し、グループの読み込みを許可する、といったことをしなければなりません。このWebサーバがアクセスしなければならないファイルの所有者がhironobuのユーザしか存在していないのならば、グループで運用するのも問題ありません。しかし、もし、hironobu以外にmasamiというユーザがいたならば、双方別々のグループを作りwww-dataを加えるといった方法が必要になります。もちろんこの方法はユーザが増えるたびにグループも増えます。&lt;br /&gt;
&lt;br /&gt;
そこでACLの登場です。www-dataのアカウントのみを直接指定してアクセスを許すといった個別の対応ができれば、これまでのUNIXのアクセス権限の手法よりもシンプルに扱うことが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
=== ACLの設定 ===&lt;br /&gt;
&lt;br /&gt;
コマンドsetfaclはaclをセットするためのものです。ユーザwww-dataに&amp;quot;r&amp;quot;だけ許可をしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ setfacl -m user:www-data:r foo.txt &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ではコマンドgetfaclを使って、どう変化したか見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt&lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 user:www-data:r--&lt;br /&gt;
 group::---&lt;br /&gt;
 mask::r--&lt;br /&gt;
 other::---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
先ほどの内容から2点変わっているのがわかるはずです。まず1点はuserの表示が増えたこと、そしてmaskという新しい項目ができたことです。maskは所有するユーザ以外に与えることのできる最大限の権限です。この場合はmaskに対して指定していないのでデフォルトの&amp;quot;r&amp;quot;が設定されています。&lt;br /&gt;
ここではwww-dataのみですが、複数のユーザに対しても同様に個別の設定をすることができます。&lt;br /&gt;
ここではユーザのみに関して説明していますが、グループに対しても複数のグループを割り当てたりすることが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さらに詳しく知るためには&lt;br /&gt;
openSUSE&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 20 Linux でのアクセス制御リスト&lt;br /&gt;
https://www.belbel.or.jp/opensuse-manuals_ja/cha-security-acls.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
やRadHat&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
システム管理者のガイド 第5章 アクセス制御リスト&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-access_control_lists&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
などのACLに関する運用ドキュメントが参考になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、この状態でls -lでファイルのパーミッションの状況をみてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % ls -l foo.txt&lt;br /&gt;
 -rw-r-----+ 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最後に&amp;quot;+&amp;quot;と表示されているのは、ACLが設定されているということを意味しています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/df.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E7%AE%A1%E7%90%86%E3%81%AE%E6%A6%82%E8%A6%81&amp;diff=1736</id>
		<title>システムにおけるパスワード管理の概要</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E7%AE%A1%E7%90%86%E3%81%AE%E6%A6%82%E8%A6%81&amp;diff=1736"/>
		<updated>2024-02-01T14:11:58Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 最後に */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== はじめに == &lt;br /&gt;
&lt;br /&gt;
パスワード管理の方法と、パスワードを入手された時の問題点を整理してみましょう。その前に、パスワードに &#039;&#039;123456&#039;&#039; や &#039;&#039;password&#039;&#039; といったものやアカウント名 &#039;&#039;admin&#039;&#039; でパスワードが &#039;&#039;admin&#039;&#039; といったものを使っている「これはひどい」といいたくなるパスワードでは、さしたる事前の準備も必要なく、いくつか試せばいいので、いくらパスワードの管理をシステム側で頑張っても無理なのはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはさすがに、愚かなパスワードとしか呼びようがありませんが、これはユーザだけが悪いわけではなく、システムがこのようなパスワードを許容すること自体が、システムの欠陥ともいえます。最近のシステムではユーザがパスワードを選ぶ際に一定の強度を満たしていない場合は警告を出したり受け付けないといったものも多く、ずいぶんと状況は改善されつつあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ある程度の複雑さをもったパスワードに関しては、これはパスワード管理ファイルをサイトから流出させ、専用のコンピュータを用意してパスワードを見つける処理を行うというのが前提となります。 2012年に発生した45万件のパスワードを流出させた[http://www.zdnet.com/the-top-10-passwords-from-the-yahoo-hack-is-yours-one-of-them-7000000815/ Yahooのケース]&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Emil Protalinski,&lt;br /&gt;
&#039;&#039;The top 10 passwords from the Yahoo hack: Is yours one of them?&#039;&#039;,&lt;br /&gt;
ZDNet,&lt;br /&gt;
July 12, 2012,&lt;br /&gt;
http://www.zdnet.com/article/the-top-10-passwords-from-the-yahoo-hack-is-yours-one-of-them/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
、2013年に発生した3,800万件のパスワードを流出させた[http://www.zdnet.com/adobe-admits-2-9m-customer-accounts-have-been-compromised-7000021546/ Adobeのケース]&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 Rachel King,&lt;br /&gt;
&#039;&#039;Adobe admits 2.9M customer accounts have been compromised&#039;&#039;,&lt;br /&gt;
ZDNet,&lt;br /&gt;
 October 3, 2013,&lt;br /&gt;
http://www.zdnet.com/article/adobe-admits-2-9m-customer-accounts-have-been-compromised/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
などがこれにあたります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下に3つのパスワード管理のパターンを説明し、次に、どのような方法でパスワードを見つけていくかの説明を加えます。&lt;br /&gt;
&lt;br /&gt;
== 管理方式からパスワード方式を分類してみる==&lt;br /&gt;
=== パスワードを防御なしに管理する ===&lt;br /&gt;
&lt;br /&gt;
 [[ファイル:Pwd-pic-1.png|450px|thumb|right|保存されているパスワードは保護されない]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パスワード認証というと、ユーザからの入力の文字列と、既に登録しているパスワードの文字列を突き合わせることだと思っている人も意外といるのではないかと思います。&lt;br /&gt;
簡単に実装することができますが、ただし、このパスワードファイルが外部に流出した時点で、サービスの存続にかかわるレベルで、システム全体のユーザ認証が崩壊します。なぜならば、そのままの形ですべてのパスワードを利用することが出来るからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイルへのアクセスをコントロールすることで安全性を保っていると理解してしまう人がいるでしょうが、逆をいえば、それだけしか保護をしておらず、情報流出する可能性の前提に立っていません。潜在的に1つのエラーがシステム全体をカタストロフな状態に導く可能性がある脆弱な状態におかれています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このシステムは、大きな問題をはらんでいるのは、改めて強調しなくとも多くの方には理解されているだろうと思います。その一方で、このようなシステムは、そんなに多くはないだろうと楽観的に考えるかも知れません。でも、パスワードを忘れたときに親切にも元々のパスワードを教えてくれるタイプのシステムは、まわりを見渡せばけっこうあるはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 利点: パスワードを忘れたときに、パスワードを教えることができる。&lt;br /&gt;
* 欠点: パスワードファイルが流出するとユーザ認証は壊滅的なダメージとなる。&lt;br /&gt;
&lt;br /&gt;
=== 一方向性ハッシュ関数を導入し管理する ===&lt;br /&gt;
&lt;br /&gt;
 [[ファイル:Pwd-pic-2.png|450px|thumb|right|一方向性ハッシュ関数のみ導入]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一方向性ハッシュ関数とは、値xに対しハッシュ関数Hを用いて計算した値H(x)から、逆をたどってxを見つけることは極めて困難であるという性質を持つ関数です。一方向性ハッシュ関数にはSHA256、SHA512といったものだけではなく、共通鍵暗号を使ったメッセージ認証コードなども同様に使えます。たとえば古典的UNIXのパスワード生成にはDES暗号を使っているDES-CBC-MAC&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
D. Wagner and I. Goldberg. ,&lt;br /&gt;
&#039;&#039;Proofs of security for the UNIX passwordhashing algorithm.&#039;&#039;,&lt;br /&gt;
Advances in Cryptology – ASIACRYPT ’00, Lecture Notes in Computer Science Vol. 1976,&lt;br /&gt;
T. Okamoto ed., Springer-Verlag, 2000. &lt;br /&gt;
http://www.cs.berkeley.edu/~daw/papers/crypt3-asia00.ps&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というメッセージ認証コード法が使われています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
よく「パスワードを暗号化」するという表現を使うので、暗号化するなら、復号もできるだろうと類推してしまいそうになりますが、これは一方向にしか計算できません。&lt;br /&gt;
パスワードを入力し、それを一方向性ハッシュ関数で計算した値を、事前に登録しておいた一方向性ハッシュ関数で計算した値と比較します。たとえばWindowsXPなどで使っていたLMハッシュ(LAN Manager hash)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
&#039;&#039;Network security: Do not store LAN Manager hash value on next password change&#039;&#039;,&lt;br /&gt;
November 15, 2012,&lt;br /&gt;
https://technet.microsoft.com/en-us/library/jj852276&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、この方式です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生の文字列を持っている先ほどの方法よりは格段に安全性は上がりますが、例えば同じ入力のものは同じ出力値を持ってしまう弱点を持っています。そのため辞書に載っているようなパスワードであれば、事前に処理してハッシュ値辞書を作成することが出来きます。つまり、辞書攻撃には極めて脆弱なパスワードシステムだといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
辞書を作るのに膨大な時間がかかると考えるかも知れませんが、英数字8文字のすべての文字の組み合わせのための逆引き辞書を作るのに秋葉原で手に入る機材レベルで30時間もあれば十分作成できます。&lt;br /&gt;
しかも[http://lasecwww.epfl.ch/~oechslin/projects/ophcrack/ ophcrack]&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Philippe Oechslin,&lt;br /&gt;
&#039;&#039;Making a Faster Crytanalytical Time-Memory Trade-Off&#039;&#039;, &lt;br /&gt;
Advances in Cryptology - CRYPTO 2003, 23rd Annual International Cryptology Conference, Santa Barbara, California, USA, August 17-21, 2003, Proceedings. Lecture Notes in Computer Science 2729 Springer 2003, ISBN 3-540-40674-3&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
サイトでは既にWindows XPやVistaのための辞書テーブルが既に用意されており、それを使えば検索成功率99パーセントだそうです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
先ほどの紹介したAdobeの流出したパスワード情報は、このタイプで、さらに悪いことには、ユーザが入力するパスワードのヒント情報も入っており、そこからまず類推可能なパスワードを探し当て、次に同じパスワードを持つユーザをピックアップしてゆくということが出来てしまうという、極めて憂慮すべきシステムでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 利点: パスワードを見つけるためにはパスワード解析をする必要がある。&lt;br /&gt;
* 欠点: 同じパスワードは同じ出力なので事前に辞書を作ることが可能。&lt;br /&gt;
&lt;br /&gt;
=== さらにソルトを加えたてパスワード管理する === &lt;br /&gt;
&lt;br /&gt;
 [[ファイル:Pwd-pic-3.png|450px|thumb|right|Salt(ソルト)を加えることにより同じパスワードの類推を困難にする]]&lt;br /&gt;
&lt;br /&gt;
一方向性ハッシュ関数だけだと逆引きの攻撃辞書が使えるので、それを困難にするようにソルト(salt)と呼ばれる、ユーザ毎に異なるランダムな値を加えたのちに一方向性ハッシュ関数に入力する方法をとります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このソルトは隠さなくてもかまいません。長ければながいほど逆引きの攻撃辞書のサイズが巨大になります。ソルトはランダムデータですが、そんなに大きなものは必要なく70年代では12ビット程度が使われており、もし将来的(といっても2020年あたりまで)にも使うと考えるとしても64ビット(8バイト)程度あれば十分でしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
古典的なUNIXのパスワード処理法では、さらに一方向性ハッシュ関数を複数回呼び出し計算時間をより多くかけさせるという手法を使っています。ただし一度に多数のユーザの対応をしなければならないようなシステム、例えばウェブサイトのパスワード認証などで行うのは、認証するサーバー側に負荷がかかりすぎる可能性があるので、本当にこの手法を選択すべきかどうかは熟慮が必要です。基本的には、複雑さを増すにはパスワードに使える文字種類を多くしたり、文字数を増やすことが重要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これでやっと普通&amp;lt;ref&amp;gt;ここでの普通は、ただ単純に広く使われているという意味ではなく、「[https://www.youtube.com/watch?v=rBX5YGPNDbs&amp;amp;t=43s 真ん中ではなく理想に近い]」という意味です。 &amp;lt;/ref&amp;gt;&lt;br /&gt;
のパスワード管理の基準を満たすことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 利点: 事前のパスワード解析を無効にできる。&lt;br /&gt;
* 欠点: なし（現状で必要な条件は満たしている）。&lt;br /&gt;
&lt;br /&gt;
==  最後に ==&lt;br /&gt;
&lt;br /&gt;
最初にいったことの繰り返しになりますが、パスワード方式そのものの弱点は利用者がたとえば&lt;br /&gt;
&#039;&#039;qwert&#039;&#039;&lt;br /&gt;
とか&lt;br /&gt;
&#039;&#039;99999&#039;&#039;&lt;br /&gt;
といった愚かなパスワードをつけてしまうと意味がなくなることです。&lt;br /&gt;
どんなにシステム側でパスワードを保護していても、人間側が愚かなパスワードを使えばなんの意味も成しません。&lt;br /&gt;
近年の各種 GNU/Linux ディストリビューションでは包括的なパスワード認証のためのフレームワークとして [http://www.linux-pam.org/ Linux-PAM] を採用しています。&lt;br /&gt;
これには弱いパスワードを受け付けないといった機能も入っています。&lt;br /&gt;
このように人間側に対しても色々な工夫をしなければ、パスワード方式は安全とはいえません。&lt;br /&gt;
人的リソースを管理をするのもオペレーティングシステムの重要な役割の1つです。&lt;br /&gt;
また、あちらこちらのパスワード認証でパスワードを使いまわしているユーザもいます。&lt;br /&gt;
どこか1つが破られたら、パスワードの使い回しているアカウントは次々に破られていきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では、すべてのアカウントですべて異なる複雑なパスワードを使えば良いのでしょうか？&lt;br /&gt;
残念ながら、人間はそんな記憶力はありません。&lt;br /&gt;
そしてそのような方式を導入して問題をユーザのパスワード管理や運用の不備に責任転嫁するのは正しいアプローチだとはいえません。&lt;br /&gt;
パスワード認証方式を取り巻く問題は色々な面で問題が浮き彫りになってきているのが現状です。&lt;br /&gt;
今後、パスワード認証方式がどれだけ生き残れるのか、あるいは生き残り続けるとして、どのような運用をすれば良いのか、そもそもパスワード認証方式の代替案があるのか、そしてまたそれは普及するのか、などなど問題は山積しているといっても過言ではないでしょう&amp;lt;ref&amp;gt;KOF2023 【招待講演】パスワード入門／ユニバーサルシェルプログラミング研究所 研究グループ　すずきひろのぶ氏 [https://www.youtube.com/watch?v=yKgVlqZEXA0  YouTube]&amp;lt;/ref&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/8b.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E7%AE%A1%E7%90%86%E3%81%AE%E6%A6%82%E8%A6%81&amp;diff=1735</id>
		<title>システムにおけるパスワード管理の概要</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E7%AE%A1%E7%90%86%E3%81%AE%E6%A6%82%E8%A6%81&amp;diff=1735"/>
		<updated>2024-02-01T14:10:59Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 最後に */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== はじめに == &lt;br /&gt;
&lt;br /&gt;
パスワード管理の方法と、パスワードを入手された時の問題点を整理してみましょう。その前に、パスワードに &#039;&#039;123456&#039;&#039; や &#039;&#039;password&#039;&#039; といったものやアカウント名 &#039;&#039;admin&#039;&#039; でパスワードが &#039;&#039;admin&#039;&#039; といったものを使っている「これはひどい」といいたくなるパスワードでは、さしたる事前の準備も必要なく、いくつか試せばいいので、いくらパスワードの管理をシステム側で頑張っても無理なのはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはさすがに、愚かなパスワードとしか呼びようがありませんが、これはユーザだけが悪いわけではなく、システムがこのようなパスワードを許容すること自体が、システムの欠陥ともいえます。最近のシステムではユーザがパスワードを選ぶ際に一定の強度を満たしていない場合は警告を出したり受け付けないといったものも多く、ずいぶんと状況は改善されつつあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ある程度の複雑さをもったパスワードに関しては、これはパスワード管理ファイルをサイトから流出させ、専用のコンピュータを用意してパスワードを見つける処理を行うというのが前提となります。 2012年に発生した45万件のパスワードを流出させた[http://www.zdnet.com/the-top-10-passwords-from-the-yahoo-hack-is-yours-one-of-them-7000000815/ Yahooのケース]&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Emil Protalinski,&lt;br /&gt;
&#039;&#039;The top 10 passwords from the Yahoo hack: Is yours one of them?&#039;&#039;,&lt;br /&gt;
ZDNet,&lt;br /&gt;
July 12, 2012,&lt;br /&gt;
http://www.zdnet.com/article/the-top-10-passwords-from-the-yahoo-hack-is-yours-one-of-them/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
、2013年に発生した3,800万件のパスワードを流出させた[http://www.zdnet.com/adobe-admits-2-9m-customer-accounts-have-been-compromised-7000021546/ Adobeのケース]&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 Rachel King,&lt;br /&gt;
&#039;&#039;Adobe admits 2.9M customer accounts have been compromised&#039;&#039;,&lt;br /&gt;
ZDNet,&lt;br /&gt;
 October 3, 2013,&lt;br /&gt;
http://www.zdnet.com/article/adobe-admits-2-9m-customer-accounts-have-been-compromised/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
などがこれにあたります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下に3つのパスワード管理のパターンを説明し、次に、どのような方法でパスワードを見つけていくかの説明を加えます。&lt;br /&gt;
&lt;br /&gt;
== 管理方式からパスワード方式を分類してみる==&lt;br /&gt;
=== パスワードを防御なしに管理する ===&lt;br /&gt;
&lt;br /&gt;
 [[ファイル:Pwd-pic-1.png|450px|thumb|right|保存されているパスワードは保護されない]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パスワード認証というと、ユーザからの入力の文字列と、既に登録しているパスワードの文字列を突き合わせることだと思っている人も意外といるのではないかと思います。&lt;br /&gt;
簡単に実装することができますが、ただし、このパスワードファイルが外部に流出した時点で、サービスの存続にかかわるレベルで、システム全体のユーザ認証が崩壊します。なぜならば、そのままの形ですべてのパスワードを利用することが出来るからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイルへのアクセスをコントロールすることで安全性を保っていると理解してしまう人がいるでしょうが、逆をいえば、それだけしか保護をしておらず、情報流出する可能性の前提に立っていません。潜在的に1つのエラーがシステム全体をカタストロフな状態に導く可能性がある脆弱な状態におかれています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このシステムは、大きな問題をはらんでいるのは、改めて強調しなくとも多くの方には理解されているだろうと思います。その一方で、このようなシステムは、そんなに多くはないだろうと楽観的に考えるかも知れません。でも、パスワードを忘れたときに親切にも元々のパスワードを教えてくれるタイプのシステムは、まわりを見渡せばけっこうあるはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 利点: パスワードを忘れたときに、パスワードを教えることができる。&lt;br /&gt;
* 欠点: パスワードファイルが流出するとユーザ認証は壊滅的なダメージとなる。&lt;br /&gt;
&lt;br /&gt;
=== 一方向性ハッシュ関数を導入し管理する ===&lt;br /&gt;
&lt;br /&gt;
 [[ファイル:Pwd-pic-2.png|450px|thumb|right|一方向性ハッシュ関数のみ導入]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一方向性ハッシュ関数とは、値xに対しハッシュ関数Hを用いて計算した値H(x)から、逆をたどってxを見つけることは極めて困難であるという性質を持つ関数です。一方向性ハッシュ関数にはSHA256、SHA512といったものだけではなく、共通鍵暗号を使ったメッセージ認証コードなども同様に使えます。たとえば古典的UNIXのパスワード生成にはDES暗号を使っているDES-CBC-MAC&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
D. Wagner and I. Goldberg. ,&lt;br /&gt;
&#039;&#039;Proofs of security for the UNIX passwordhashing algorithm.&#039;&#039;,&lt;br /&gt;
Advances in Cryptology – ASIACRYPT ’00, Lecture Notes in Computer Science Vol. 1976,&lt;br /&gt;
T. Okamoto ed., Springer-Verlag, 2000. &lt;br /&gt;
http://www.cs.berkeley.edu/~daw/papers/crypt3-asia00.ps&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というメッセージ認証コード法が使われています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
よく「パスワードを暗号化」するという表現を使うので、暗号化するなら、復号もできるだろうと類推してしまいそうになりますが、これは一方向にしか計算できません。&lt;br /&gt;
パスワードを入力し、それを一方向性ハッシュ関数で計算した値を、事前に登録しておいた一方向性ハッシュ関数で計算した値と比較します。たとえばWindowsXPなどで使っていたLMハッシュ(LAN Manager hash)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
&#039;&#039;Network security: Do not store LAN Manager hash value on next password change&#039;&#039;,&lt;br /&gt;
November 15, 2012,&lt;br /&gt;
https://technet.microsoft.com/en-us/library/jj852276&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、この方式です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生の文字列を持っている先ほどの方法よりは格段に安全性は上がりますが、例えば同じ入力のものは同じ出力値を持ってしまう弱点を持っています。そのため辞書に載っているようなパスワードであれば、事前に処理してハッシュ値辞書を作成することが出来きます。つまり、辞書攻撃には極めて脆弱なパスワードシステムだといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
辞書を作るのに膨大な時間がかかると考えるかも知れませんが、英数字8文字のすべての文字の組み合わせのための逆引き辞書を作るのに秋葉原で手に入る機材レベルで30時間もあれば十分作成できます。&lt;br /&gt;
しかも[http://lasecwww.epfl.ch/~oechslin/projects/ophcrack/ ophcrack]&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Philippe Oechslin,&lt;br /&gt;
&#039;&#039;Making a Faster Crytanalytical Time-Memory Trade-Off&#039;&#039;, &lt;br /&gt;
Advances in Cryptology - CRYPTO 2003, 23rd Annual International Cryptology Conference, Santa Barbara, California, USA, August 17-21, 2003, Proceedings. Lecture Notes in Computer Science 2729 Springer 2003, ISBN 3-540-40674-3&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
サイトでは既にWindows XPやVistaのための辞書テーブルが既に用意されており、それを使えば検索成功率99パーセントだそうです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
先ほどの紹介したAdobeの流出したパスワード情報は、このタイプで、さらに悪いことには、ユーザが入力するパスワードのヒント情報も入っており、そこからまず類推可能なパスワードを探し当て、次に同じパスワードを持つユーザをピックアップしてゆくということが出来てしまうという、極めて憂慮すべきシステムでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 利点: パスワードを見つけるためにはパスワード解析をする必要がある。&lt;br /&gt;
* 欠点: 同じパスワードは同じ出力なので事前に辞書を作ることが可能。&lt;br /&gt;
&lt;br /&gt;
=== さらにソルトを加えたてパスワード管理する === &lt;br /&gt;
&lt;br /&gt;
 [[ファイル:Pwd-pic-3.png|450px|thumb|right|Salt(ソルト)を加えることにより同じパスワードの類推を困難にする]]&lt;br /&gt;
&lt;br /&gt;
一方向性ハッシュ関数だけだと逆引きの攻撃辞書が使えるので、それを困難にするようにソルト(salt)と呼ばれる、ユーザ毎に異なるランダムな値を加えたのちに一方向性ハッシュ関数に入力する方法をとります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このソルトは隠さなくてもかまいません。長ければながいほど逆引きの攻撃辞書のサイズが巨大になります。ソルトはランダムデータですが、そんなに大きなものは必要なく70年代では12ビット程度が使われており、もし将来的(といっても2020年あたりまで)にも使うと考えるとしても64ビット(8バイト)程度あれば十分でしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
古典的なUNIXのパスワード処理法では、さらに一方向性ハッシュ関数を複数回呼び出し計算時間をより多くかけさせるという手法を使っています。ただし一度に多数のユーザの対応をしなければならないようなシステム、例えばウェブサイトのパスワード認証などで行うのは、認証するサーバー側に負荷がかかりすぎる可能性があるので、本当にこの手法を選択すべきかどうかは熟慮が必要です。基本的には、複雑さを増すにはパスワードに使える文字種類を多くしたり、文字数を増やすことが重要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これでやっと普通&amp;lt;ref&amp;gt;ここでの普通は、ただ単純に広く使われているという意味ではなく、「[https://www.youtube.com/watch?v=rBX5YGPNDbs&amp;amp;t=43s 真ん中ではなく理想に近い]」という意味です。 &amp;lt;/ref&amp;gt;&lt;br /&gt;
のパスワード管理の基準を満たすことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 利点: 事前のパスワード解析を無効にできる。&lt;br /&gt;
* 欠点: なし（現状で必要な条件は満たしている）。&lt;br /&gt;
&lt;br /&gt;
==  最後に ==&lt;br /&gt;
&lt;br /&gt;
最初にいったことの繰り返しになりますが、パスワード方式そのものの弱点は利用者がたとえば&lt;br /&gt;
&#039;&#039;qwert&#039;&#039;&lt;br /&gt;
とか&lt;br /&gt;
&#039;&#039;99999&#039;&#039;&lt;br /&gt;
といった愚かなパスワードをつけてしまうと意味がなくなることです。&lt;br /&gt;
どんなにシステム側でパスワードを保護していても、人間側が愚かなパスワードを使えばなんの意味も成しません。&lt;br /&gt;
近年の各種 GNU/Linux ディストリビューションでは包括的なパスワード認証のためのフレームワークとして [http://www.linux-pam.org/ Linux-PAM] を採用しています。&lt;br /&gt;
これには弱いパスワードを受け付けないといった機能も入っています。&lt;br /&gt;
このように人間側に対しても色々な工夫をしなければ、パスワード方式は安全とはいえません。&lt;br /&gt;
人的リソースを管理をするのもオペレーティングシステムの重要な役割の1つです。&lt;br /&gt;
また、あちらこちらのパスワード認証でパスワードを使いまわしているユーザもいます。&lt;br /&gt;
どこか1つが破られたら、パスワードの使い回しているアカウントは次々に破られていきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では、すべてのアカウントですべて異なる複雑なパスワードを使えば良いのでしょうか？&lt;br /&gt;
残念ながら、人間はそんな記憶力はありません。&lt;br /&gt;
そしてそのような方式を導入して問題をユーザのパスワード管理や運用の不備に責任転嫁するのは正しいアプローチだとはいえません。&lt;br /&gt;
パスワード認証方式を取り巻く問題は色々な面で問題が浮き彫りになってきているのが現状です。&lt;br /&gt;
今後、パスワード認証方式がどれだけ生き残れるのか、あるいは生き残り続けるとして、どのような運用をすれば良いのか、そもそもパスワード認証方式の代替案があるのか、そしてまたそれは普及するのか、などなど問題は山積しているといっても過言ではないでしょう&amp;lt;ref&amp;gt;KOF2023 【招待講演】パスワード入門／ユニバーサルシェルプログラミング研究所 研究グループ　すずきひろのぶ氏 [https://www.youtube.com/watch?v=yKgVlqZEXA0 / YouTube]&amp;lt;/ref&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/8b.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=Linux_LVM&amp;diff=1734</id>
		<title>Linux LVM</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=Linux_LVM&amp;diff=1734"/>
		<updated>2023-09-09T07:49:54Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 脚注 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== LVM 論理ボリュームマネージャー ==&lt;br /&gt;
&lt;br /&gt;
=== LVMとは  === &lt;br /&gt;
&lt;br /&gt;
LVM (Logical Volume Manager)は、物理的なボリュームを論理グループにまとめ、そこから論理ボリュームとして取り出した利用領域をパーティションなどに用いるための仕組みです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このような仕組みがない場合、ハードディスクのパーティションを、そのままファイルシステムに使うことになります。このような運用方法で、例えば後からパーティションサイズを増やし、ファイルシステムのサイズを拡大させるといったことを運用しながら行うことは手間と作業する時間がかかります。柔軟な運用をしたい場合、LVMを用いてこのような問題を解決することができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LVMは90年代後半にHP-UX (ヒューレッド・パーカード社のUNIX)に搭載された機能で、後にLinuxのディストリビューションに広く採用されました。現在ではメジャーなディストリビューションではrootファイルシステムはデフォルトでLVMの論理ボリューム上に構築されています。&lt;br /&gt;
&lt;br /&gt;
=== 論理ボリュームグループ  === &lt;br /&gt;
&lt;br /&gt;
ハードディスクなどのブロックデバイスにLVM専用のパーティションを用意する必要があります。パーティションのIDは8eです。&lt;br /&gt;
それが（登録されると）物理ボリューム(PV: Physical Volume)として扱われます。&lt;br /&gt;
&lt;br /&gt;
論理ボリュームグループ(VG: Logical Volume Group) は、1つもしくは複数のPVからなるボリュームのプールです。そのプールから今度はVGのサイズを上限とした任意のサイズの論理ボリューム(LV: Logical Volume)を取り出します。これにより、複数のパーティションをVGにPVとして登録しているならば、LVはその1つのパーティションよりも大きく取ることが可能です。これまでハードディスクの物理的サイズが上限であったファイルシステムのサイズを、今度は論理ボリューム（論理ボリュームグループ）のサイズを上限に出きるようになります。&lt;br /&gt;
&lt;br /&gt;
[[ファイル:Lvm-pic-1.png|380px]]&lt;br /&gt;
&lt;br /&gt;
=== LVMの操作方法 ===&lt;br /&gt;
[[LVMの構築方法]] では、まだLVMを利用していない場合、最初から構築する方法を説明します。&lt;br /&gt;
現在、多くのディストリビューションでLVMはデフォルトで導入されていますので、&lt;br /&gt;
構築する方法部分の説明を省き、追加する説明だけで十分かも知れません。&lt;br /&gt;
その場合は [[LVMの追加方法]] を参照ください。&lt;br /&gt;
LVMを使ってのスナップショットは[[LVMを使ってスナップショット]]を参考にして下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== リンク ==&lt;br /&gt;
&lt;br /&gt;
*  [[LVMの構築方法]] &lt;br /&gt;
*   [[LVMの追加方法]] &lt;br /&gt;
*  [[LVMを使ってスナップショット]]&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
*  [https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/pdf/logical_volume_manager_administration/red_hat_enterprise_linux-7-logical_volume_manager_administration-ja-jp.pdf Red Hat Enterprise Linux 7 論理ボリュームマネージャーの管理]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/20.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1733</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1733"/>
		<updated>2023-08-18T12:13:28Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* スケジューラのチューニング */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  GNU/Linux上で円周率の計算をおこなう http://h2np.net/pi/&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下3300万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、数十分、あるいは数時間という具合に長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;追記: その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、&lt;br /&gt;
&lt;br /&gt;
あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== スケジューラのチューニング ====&lt;br /&gt;
&lt;br /&gt;
スケジューラのチューニングに関しては下記の情報が参考になります。&lt;br /&gt;
&lt;br /&gt;
* SUSE [https://www.belbel.or.jp/opensuse-manuals_ja/cha-tuning-taskscheduler.html タスクスケジューラのチューニング]&lt;br /&gt;
&lt;br /&gt;
* Red Hat Enterprise Linux 9 [https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/pdf/monitoring_and_managing_system_status_and_performance/red_hat_enterprise_linux-9-monitoring_and_managing_system_status_and_performance-ja-jp.pdf 第30章 スケジューリングポリシーの調整]&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が低く、大きいものが実行優先順位が高くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1732</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1732"/>
		<updated>2023-08-18T12:11:46Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* CFS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  GNU/Linux上で円周率の計算をおこなう http://h2np.net/pi/&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下3300万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、数十分、あるいは数時間という具合に長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;追記: その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、&lt;br /&gt;
&lt;br /&gt;
あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== スケジューラのチューニング ====&lt;br /&gt;
&lt;br /&gt;
スケジューラのチューニングに関しては下記の情報が参考になります。&lt;br /&gt;
&lt;br /&gt;
- SUSE [タスクスケジューラのチューニング](https://www.belbel.or.jp/opensuse-manuals_ja/cha-tuning-taskscheduler.html)&lt;br /&gt;
- Red Hat Enterprise Linux 9 [第30章 スケジューリングポリシーの調整] (https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/9/pdf/monitoring_and_managing_system_status_and_performance/red_hat_enterprise_linux-9-monitoring_and_managing_system_status_and_performance-ja-jp.pdf)&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が低く、大きいものが実行優先順位が高くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1731</id>
		<title>ユーザ権限とアクセス制御</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1731"/>
		<updated>2023-02-24T06:10:02Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* ACL */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== ユーザと権限  ==&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステム内部ではユーザの違いをアカウント名ではなく&lt;br /&gt;
ユーザID(UID / User IDentifier)による数値で認識しています。&lt;br /&gt;
またユーザは1つデフォルトのグループID(GID / GroupIDentifier)がつけられています。&lt;br /&gt;
そのユーザIDやグループIDが条件に合致するかどうかでユーザに権限があるかどうかを判断しています。&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
RED HAT ENTERPRISE LINUX Identity Management ガイド&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/identity_management_guide/index&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: ユーザやグループの追加、更新などオペレーションに関しては[[ユーザやグループの管理]]を参照してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
唯一例外的なのはユーザIDが0、グループIDが0のユーザrootです。&lt;br /&gt;
スーパーユーザーと呼ばれ、&lt;br /&gt;
UNIXにおいてはオールマイティーな権限を持つ特別なユーザです。&lt;br /&gt;
管理者権限として説明される場合が多いのですが、&lt;br /&gt;
管理者として何かするという表現よりも「オペレーティングシステム上で何でもできてしまう権限」&lt;br /&gt;
と説明した方が分かり易いかと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ユーザIDとグループIDによるアクセス制御 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの内部では、ユーザは名前で管理されているのではなくユーザID(UID)で管理されています。&lt;br /&gt;
たとえばファイルにユーザ(所有者)が設定されていますが、その所有者情報とはファイルの情報（ディレクトリ情報のなかにあるメタ情報）に付加されているユーザIDのことです。&lt;br /&gt;
また、プロセスが動作している時には、いずれかのユーザIDとグループIDを持っており、そのユーザIDに付加された権限の範囲内においてプロセスは資源にアクセスできます。&lt;br /&gt;
グループID(GID)は、そのグループにユーザが登録されている場合、そのユーザに与えられるグループ権限です。&lt;br /&gt;
UNIXの基本的な権限は、このユーザIDの違いによるユーザ権限と、グループIDの違いによるグループ権限の2つから成り立っています。&lt;br /&gt;
ファイルやプロセスの資源へのアクセス制御はユーザID・グループID&lt;br /&gt;
&amp;lt;ref&amp;gt;自分のユーザIDやグループIDを確認するにはコマンドidを使う。詳しくは[[ユーザやグループの管理]]を参照のこと。&amp;lt;/ref&amp;gt;&lt;br /&gt;
を使っての許可・不許可によって行われるというのが基本的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずファイルに対するユーザIDとグループIDを見てみましょう。&lt;br /&gt;
ファイルには、ユーザIDとグループIDが設定されています。&lt;br /&gt;
ユーザID＝このファイルの所有者です。&lt;br /&gt;
尚、本章の範囲では、所有者とユーザと同じ意味で使っています。&lt;br /&gt;
ユーザが自分の所有するファイルの属性を変更し、そのファイルのアクセス権限などをコントロールすることができます。&lt;br /&gt;
ただしroot権限だけは例外で、システムのすべてに無制限にアクセスできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ユーザIDが数字ではなくユーザ名として表示されるのは、ユーザIDは/etc/passwdで設定されている対応するアカウント名、&lt;br /&gt;
グループIDは/etc/groupで設定されている対応するグループ名に変換されて表示されるからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 読み込み / 書き込み  / 実行 ===&lt;br /&gt;
&lt;br /&gt;
基本的なファイルへのアクセス権限は、「読み込み」「書き込み」「実行」です。&lt;br /&gt;
ディレクトリの場合は実行の部分の意味が「ディレクトリとしてアクセスできるか」ということとして扱われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*  アクセス権限 : 読み込み / 書き込み / 実行&lt;br /&gt;
*  ユーザ・所有者(User)に対して : 許可 / 不許可&lt;br /&gt;
*  グループ(Group)に対して : 許可 / 不許可&lt;br /&gt;
*  それ以外(Other)対して : 許可 / 不許可&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-r--r--    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
 $  ls -l /var/mail/hironobu&lt;br /&gt;
 -rw-rw----    1 hironobu mail            0 Dec  9 19:39 hironobu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
memo.txtはユーザIDがhironobu、グループIDがhironobuになっており、ユーザ（所有者）は読み書き、同じグループには読み込み、その他の権限でも読み込みができます。&lt;br /&gt;
正確には、ユーザと同じユーザIDを持ったプロセス、設定されたグループと同じグループに属するユーザIDを持つプロセス、それ以外のユーザIDを持つプロセスがアクセス可能であるという表現になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/var/mail/hironobuというファイルのユーザIDはhironobuになっており、グループIDはmailです。mailのグループ権限を持つプロセスから読み書き可能になっています。具体的には、メールサーバなどのプロセスが読み書きできるようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
変更はコマンドchmodを使います。chmodのオプションではユーザ（所有者）はu、グループはg、それ以外の利用者はoという表現を使います。&lt;br /&gt;
パーミッションの許可は&amp;quot;+&amp;quot;、パーミッションの不許可は&amp;quot;-&amp;quot;を使います。&lt;br /&gt;
chmodのオプションで&amp;quot;go-rw&amp;quot;はグループとその他ユーザからの読み書きは不許可となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ユーザ（所有者）、グループ、その他ユーザの読み取り許可・不許可、書き込み許可・不許可、実行の許可・不許可は3ビットで表すので、この部分を8進数で表現することもできます。&lt;br /&gt;
その場合&amp;quot;rw-------&amp;quot;はビットの設定がuが110、gが000、oが000となるので、8進数表現をするモードでは600となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 600 memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== グループID利用の方法 == &lt;br /&gt;
&lt;br /&gt;
ここにファイルgroup_share.datがあるとします。これをユーザtaroとユーザhanakoが共通に読み書きのアクセスでき、&lt;br /&gt;
他のユーザはアクセスできないようなパーミッションにしたいとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-r--r--  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずgroup_share.datを所有者とグループにはrw、それ以外には読み書き禁止にします。&lt;br /&gt;
chmodを使いますが、2度に分けてオプションを使ってもいいですし、モードを数字で与えてもかまいません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod o-wr group_share.dat &lt;br /&gt;
 $ chmod g+wr group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
あるいは&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 660 group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
結果は次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-rw----  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次にroot権限でtaroとhanakoの共通に使えるグループtaro-hanakoを作ります。&lt;br /&gt;
そしてtaro とhanakoをグループtaro-hanakoに加えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 # groupadd taro-hanako&lt;br /&gt;
 # gpasswd -a taro   taro-hanako&lt;br /&gt;
 # gpasswd -a hanako taro-hanako&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
taroが新しいグループに加わった時、taroが再度ログインした時からその新しいグループ (この場合taro-hanako)が有効になります。&lt;br /&gt;
再度ログインした状態で、taroはgroup_share.datのグループIDをtaro-hanakoにします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chgrp taro-hanako group_share.dat&lt;br /&gt;
 ...&lt;br /&gt;
 -rw-rw----  1 taro taro-hanako     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これでgroup_share.datはtaro-hanakoのグループに属しているtaroとhanakoが読み書きが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;考えてみよう: apacheはユーザwww-dataの権限で動作しています。cgi-binなどでコマンドを動かしファイルinfo.datに情報を書き込む必要があります。しかし、info.dataの中身に関してはセキュリティ上の問題のためユーザfoo以外には読ませたくありません(www-dataにも許可しません)。さて、この場合、info.datの適切なファイルの所有者、適切なパーミッションはどのようなものでしょうか。&lt;br /&gt;
&lt;br /&gt;
== プロセスのユーザIDとグループID ==&lt;br /&gt;
&lt;br /&gt;
まずログインした時に、そのアカウント名に割り振られたユーザIDとグループIDの権限でログインシェルが動き始めます。&lt;br /&gt;
そのシェルから起動されるプロセスにはデフォルトで親プロセスのユーザIDとグループIDが受け継がれます。&lt;br /&gt;
root権限(注)でsetuid(2)やsetgid(2)を使うとプロセスのユーザIDを変更することができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: setuid(2)やsetgid(2)の利用にはもう少し限定した条件があるので調べてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps aux&lt;br /&gt;
 USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND&lt;br /&gt;
 root         1  0.0  0.0  1272  432 ?        S    Aug23   1:49 init [2]       &lt;br /&gt;
 ...&lt;br /&gt;
 daemon     126  0.0  0.0  1384  296 ?        S    Aug23   0:00 /sbin/portmap&lt;br /&gt;
 canna     2799  0.0  2.7 19152 17568 ?       S    Aug23  13:02 /usr/sbin/cannase&lt;br /&gt;
 root     23439  0.0  0.1  2936  660 ?        S    Nov24   0:17 /usr/sbin/apache&lt;br /&gt;
 www-data 23474  0.0  0.0  2948  632 ?        S    Nov24   0:00 /usr/sbin/apache&lt;br /&gt;
 hironobu 20287  0.0  0.0  2464  224 pts/0    S    Oct16   0:00 bash&lt;br /&gt;
 hironobu  2796  0.0  1.0  8752 6716 ?        R    12:14   0:05 emacs20 -geometry&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 現在の権限管理 === &lt;br /&gt;
&lt;br /&gt;
古典的なUNIXはUIDとGIDだけで説明は済みますが、Linuxも含めBSD 4.3以降では、もっと複雑な設定ができます。&lt;br /&gt;
Linuxでは4つタイプのUIDと4つのGIDのタイプを持っています。&lt;br /&gt;
&lt;br /&gt;
*  ユーザID、グループIDの種類&lt;br /&gt;
* UID / GID : 今まで通りのUID / GID &lt;br /&gt;
* RUID / RGID : 実UID / 実GID --- UIDやGIDと同じ役割 (RはReal)&lt;br /&gt;
* EUID / EGID : 実効UID / 実効GID --- 権限があるかどうかをチェックする時に使う (EはEffective)&lt;br /&gt;
* SUID / SGID : 保存UID / 保存GID --- 有効化・無効化を行うための保存 (SはSaved)&lt;br /&gt;
* FSUID / FSGID : ファイルUID / ファイルGID --- Linux独自のファイルのアクセス権限のチェック&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== setuid  === &lt;br /&gt;
&lt;br /&gt;
これらはプロセスが、どのような権限で動作するかを規定するものです。&lt;br /&gt;
UNIXには実行ファイルの属性に(モードに)setuid bitを設定しておくと、&lt;br /&gt;
その実行ファイルはファイルの所有者の権限で動作します。&lt;br /&gt;
setgid bitは実行ファイルのグループの権限で動作します。&lt;br /&gt;
コマンドfindを使って探してみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +a+s -exec ls -l {} \;&lt;br /&gt;
 -rwsr-xr-x 1 root root 26252 Mar  3  2012 /bin/fusermount&lt;br /&gt;
 -rwsr-xr-x 1 root root 88760 Mar 30  2012 /bin/mount&lt;br /&gt;
 -rwsr-xr-x 1 root root 34740 Nov  8  2011 /bin/ping&lt;br /&gt;
 -rwsr-xr-x 1 root root 39116 Nov  8  2011 /bin/ping6&lt;br /&gt;
 -rwsr-xr-x 1 root root 31116 Sep 13  2012 /bin/su&lt;br /&gt;
 -rwsr-xr-x 1 root root 67720 Mar 30  2012 /bin/umount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初の表示にある-rwsr-x-rxのsがsetuid bitの意味です。&lt;br /&gt;
つまり、これらのコマンドは所有者がrootであり、かつ、&lt;br /&gt;
このコマンドを動かすとrootの権限で動かすことができるという意味です。&lt;br /&gt;
この実行時は、ruidは利用者、euidがrootとなり、&lt;br /&gt;
root権限のファイルなどに書き込むことができるようになります。&lt;br /&gt;
一般ユーザでも何でもできる権限を手に入れてしまうということで、&lt;br /&gt;
このようなプログラムに誤りがあると大きなセキュリティ上の問題になります。&lt;br /&gt;
&lt;br /&gt;
=== setgid === &lt;br /&gt;
&lt;br /&gt;
setgidは、set group id bitの意味です。そのファイルのグループIDと同じ権限で実行できます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +g+s -exec ls -l {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ruidがrootの時、つまりrootがファイルを実行した時は何でもできるので、euidをプロセス内で制限なく変更できます。&lt;br /&gt;
たとえばapacheは唯一1つrootでのプロセスがあり、&lt;br /&gt;
そこから生成し子プロセスがwww-data（あるいは他の）euidで動作します。&lt;br /&gt;
外部からのアクセスはすべてwww-dataのeuidで動いている子プロセスで動作しているので、&lt;br /&gt;
万が一、外部からの入力によりapache誤った動作をしても、&lt;br /&gt;
その影響範囲を無制限にはしない（root権限ではない）ようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RUID/RGID、EUID/EGID、SUID/SGIDを上手に変更することによって、どのユーザ権限で、&lt;br /&gt;
あるいはどのグループ権限でプロセスを動かし、適切にファイルや資源にアクセスできるようになることで、&lt;br /&gt;
セキュリティを保つことができるようになります。&lt;br /&gt;
これらの値のセットにはルールがあるので、全部はかけないですが、典型的なものを書き出してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* RUID / EUID / SUIDの設定ルール&lt;br /&gt;
*  RUID の値を  EUID にセットできる&lt;br /&gt;
* EUID の値を  RUID にセットできる&lt;br /&gt;
* 実行時のEUIDがSUIDにコピーされていて、SUIDの値をEUIDにセットできる&lt;br /&gt;
* rootはRUIDもEUIDも自由にセットできる&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように実行時のユーザIDを変えることができ、また一般ユーザでも実行ファイルに権限が附加されていれば、&lt;br /&gt;
root権限でプロセスを動かすこともできるなどかなり複雑な権限のコントロールが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もちろん、Linuxがコントロールが可能であることと、&lt;br /&gt;
アプリケーションがきちんと矛盾なく利用できるように設計できることとはまったく別のことです。&lt;br /&gt;
アプリケーションの設計が正しくなかったり、実装で間違えていると、セキュリティ侵害が発生することはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== なるべくrootでは動かさない運用 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まだセキュリティなどをあまり気にせず、サーバとして動作しているものは何でもかんでもrootで実行していた時期がUNIXにもありました。&lt;br /&gt;
これの利点は、アクセスする先のファイルのパーミッションやroot権限でしかオープンできないポート番号など一々気にしなくてもかまわないという点です。&lt;br /&gt;
しかし、万が一、このサーバプロセスが何かの形で乗っ取られてしまい侵入者が外部から任意のコマンドを動かすことが出来るなら、侵入者にシステムに対して万能の権限を持ってしまうことになります。&lt;br /&gt;
現在では実行権限はなるべく絞る形で運用されています。&lt;br /&gt;
たとえばhttpd(apache)は1つだけrootで稼働しポートのオープンや子プロセスを生成するといった処理をします。&lt;br /&gt;
実際のHTTPリクエストに対する対応は別の権限を与えて実行しています。たとえば下の例だとapache/apacheの権限でプロセスを動作させています。&lt;br /&gt;
万が一、外部から不当なコマンドが動かされる事態になっても、apacheのユーザ権限が及ぶ範囲でしか被害がありません。&lt;br /&gt;
システムの書き換えなど重大なセキュリティ侵害からシステムを守り被害を最小限にできるようなシステムの設計にするのが現在の一般的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
% ps -eo user,group,args | grep httpd&lt;br /&gt;
root     root     /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ディレクトリへの特殊な設定 ==&lt;br /&gt;
=== ディレクトリにsetgidビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ディレクトリのグループにsetgidビットを設定すると、そのディレクトリ以下に作られるファイル及びディレクトリには現ディレクトリのグループが適用されます。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ls -l&lt;br /&gt;
合計 4&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:35 foo&lt;br /&gt;
$ sudo touch foo/fileA&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:36 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
この例は、fooというディレクトリがあり、そのディレクトリ下にコマンド touch を使いrootの持ち物である fileA を作成します。&lt;br /&gt;
この時のfileAの所有者、グループともrootです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ chmod g+s foo&lt;br /&gt;
$ ls -ld foo&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:36 foo&lt;br /&gt;
$ sudo touch foo/fileB&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:37 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
-rw-r----- 1 root     hironobu    0 12月 14 02:37 fileB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ディレクトリ foo に対しsetgid ビットの設定を行います。setgid ビットがセットされるとグループの&amp;quot;x&amp;quot;だった部分が&amp;quot;s&amp;quot;に変化します。&lt;br /&gt;
次にコマンド touch で fileB を作成します。 &lt;br /&gt;
ディレクトリのグループ hironobu がファイルに継承されて fileB の所有者は root グループが hironobu になります。&lt;br /&gt;
&lt;br /&gt;
=== ディレクトリにStickyビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ユーザ(user)が読み書きできるディレクトリにStickyビットを設定した場合、そのディレクトリにどのユーザでもファイルを作成することができますが、ディレクトリから削除する場合、そのファイルの所有者(owner)しか削除できません。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ mkdir temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxr----- 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
$ chmod go+rwxt temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxrwxrwt 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ACL ==&lt;br /&gt;
&lt;br /&gt;
Access Control Lists（ACL）は元々のUNIXにはないアクセス制御方式で、その仕様に関してはPOSIXで定義されています。Linuxカーネル2.6以降で採用されています。Linuxカーネル2.6以降ではLinuxの主要ファイルシステムで利用可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXでは自分以外のユーザにアクセスを許可する場合は、グループに許可するか、それともすべてのユーザに許可するかの大まかな条件でアクセス制御をしています。一方、ACLではアクセス許可を特定のユーザの単位で、あるいはグループ単位で設定できます。ACLの導入により、これまでのUNIXのアクセス制御よりも限定的な設定をすることが可能になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次のようなファイルがあるとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $touch foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw-rw-r-- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コマンドgetfaclを使ってパーミッションを表示すると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt &lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 group::rw-&lt;br /&gt;
 other::r--&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次に自分以外のユーザが読み書きできないようにしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw------- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この状態でwww-dataユーザのみにfoo.txtの読み込みを許諾するとなると、グループを使う方法だとwww-dataとhironobuだけのグループを作り、そのグループを設定し、グループの読み込みを許可する、といったことをしなければなりません。このWebサーバがアクセスしなければならないファイルの所有者がhironobuのユーザしか存在していないのならば、グループで運用するのも問題ありません。しかし、もし、hironobu以外にmasamiというユーザがいたならば、双方別々のグループを作りwww-dataを加えるといった方法が必要になります。もちろんこの方法はユーザが増えるたびにグループも増えます。&lt;br /&gt;
&lt;br /&gt;
そこでACLの登場です。www-dataのアカウントのみを直接指定してアクセスを許すといった個別の対応ができれば、これまでのUNIXのアクセス権限の手法よりもシンプルに扱うことが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
=== ACLの設定 ===&lt;br /&gt;
&lt;br /&gt;
コマンドsetfaclはaclをセットするためのものです。ユーザwww-dataに&amp;quot;r&amp;quot;だけ許可をしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ setfacl -m user:www-data:r foo.txt &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ではコマンドgetfaclを使って、どう変化したか見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt&lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 user:www-data:r--&lt;br /&gt;
 group::---&lt;br /&gt;
 mask::r--&lt;br /&gt;
 other::---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
先ほどの内容から2点変わっているのがわかるはずです。まず1点はuserの表示が増えたこと、そしてmaskという新しい項目ができたことです。maskは所有するユーザ以外に与えることのできる最大限の権限です。この場合はmaskに対して指定していないのでデフォルトの&amp;quot;r&amp;quot;が設定されています。&lt;br /&gt;
ここではwww-dataのみですが、複数のユーザに対しても同様に個別の設定をすることができます。&lt;br /&gt;
ここではユーザのみに関して説明していますが、グループに対しても複数のグループを割り当てたりすることが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さらに詳しく知るためには&lt;br /&gt;
openSUSE&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 20 Linux でのアクセス制御リスト&lt;br /&gt;
https://www.belbel.or.jp/opensuse-manuals_ja/cha-security-acls.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
やRadHat&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
システム管理者のガイド 第5章 アクセス制御リスト&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-access_control_lists&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
などのACLに関する運用ドキュメントが参考になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、この状態でls -lでファイルのパーミッションの状況をみてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % ls -l foo.txt&lt;br /&gt;
 -rw-r-----+ 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最後に&amp;quot;+&amp;quot;と表示されているのは、ACLが設定されているということを意味しています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/df.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86&amp;diff=1730</id>
		<title>記憶管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86&amp;diff=1730"/>
		<updated>2022-11-17T15:17:44Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 動的なメモリ領域確保 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 実メモリ ==&lt;br /&gt;
&lt;br /&gt;
まず混乱を避けるためにメモリというあまりにも普段使い慣れた言葉を明確にしましょう。この節で使うメモリという言葉は、ハードウェア部品のメモリのことではなく、オペレーティングシステムが管理し参照できる主記憶や仮想記憶もすべて含めた記憶領域の意味です。ですから、ここでのメモリという言葉は概念的でもあり、また実際に存在するものでもある両方の性質を持ちます。ここではハードウェアのメモリにあたるものとして実メモリという言葉を使います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
メモリは重要なリソースである上に、しかも注意深く管理しなければならない&lt;br /&gt;
ものであるのは、いまさら言うまでもありません。メモリ上に実行コードやデー&lt;br /&gt;
タが展開されていて、それに対し正しいアクセス制御できなければシステムは&lt;br /&gt;
正常に動かなくなってしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリはいうまでもなく限定された貴重な資源です。実メモリはプログラムが使うだけでなく、I/Oのキャッシュに使ってI/Oパフォーマンスを改善することにも使います。&lt;br /&gt;
もしプログラムの中で既にアクセスされないメモリ空間を実メモリにかかえていていて、実メモリをキャッシュに使えないような場合は、せっかくの実メモリが有効に使えていない状態になってしまいます。&lt;br /&gt;
そこでプログラムが抱えたまま使っていないメモリ空間を外部記憶装置に送り出し、その分の実メモリをI/Oのキャッシュに利用するならば、全体のパフォーマンスが向上するはずです。このようにプログラムに使うメモリ空間を管理するだけでなくシステム全体を通して実メモリを有効に使うことが重要になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ページ ====&lt;br /&gt;
&lt;br /&gt;
[[File:Memory_fig1.png|thumb|right|300px|シンプルなアクセスモデル]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスからアクセスできるメモリリソースを考えてみましょう。&lt;br /&gt;
単純なモデルにしてみると右図のようにCPUリソースからメモリリソースに対しアクセスし読み書きする形になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、みなさんは今時の記憶管理はこのような単純なモデルではなく、物理的なメモリサイズよりも大きなメモリ空間を扱える仮想記憶があることは既に承知しているはずです。&lt;br /&gt;
仮想記憶はメモリ空間をページと呼ばれる一定サイズのフレーム（区分）にし、&lt;br /&gt;
そのページをハードディスクのような外部記憶装置と物理的なメモリである実メモリ間で書き出し、&lt;br /&gt;
読み込みを行うことによって、&lt;br /&gt;
実際の実メモリの容量よりも多くのメモリ空間を使えるようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この書き込みや読み込みをする単位をページと呼びます。扱えるページのサイズはCPU依存&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
これらはCPUのアーキテクチャーに依存するので異なる場合があります。例えばIBM POWER5+ や POWER6 プロセッサーは64KBのページサイズも利用することが出来ます。&lt;br /&gt;
&lt;br /&gt;
([https://www.ibm.com/support/knowledgecenter/ssw_aix_72/performance/multiple_page_size_support.html Multiple page size support])&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
x86-64(Intel 64)アーキテクチャーの場合2MBと1GBの拡大したページサイズが使えます。&lt;br /&gt;
([https://software.intel.com/sites/default/files/managed/a4/60/325384-sdm-vol-3abcd.pdf Intel 64 and IA-32 Architectures Software Developer’s Manual])&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ですが、多くのCPUの最小ページサイズが4KBなのでLinuxのページサイズはデフォルトで4KBとなっています。&lt;br /&gt;
&lt;br /&gt;
==== MMU ====&lt;br /&gt;
&lt;br /&gt;
[[File:Memory_fig2.png|thumb|left|300px|仮想記憶のモデル]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスに割り当てられているメモリリソースとしてのメモリのアドレスは仮想的なアドレス空間に割り当てられます。仮想アドレス空間での仮想アドレスは、実際の実メモリの物理的な意味でのアドレスとは一致しません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
仮想アドレス空間と実メモリアドレス空間のマッピングは、それを管理する MMU (Memory Management Unit) というハードウェアによってマップされています。&lt;br /&gt;
今時はMMU はCPUチップ上に組み込まれていますが、概念的にはCPUとは違うハードウェアです。&lt;br /&gt;
むかしはCPUの中に入っていなかったので、CPUとは別にMMUのチップ&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
MC68851: paged memory management unit user&#039;s manual (1986) [http://portal.acm.org/citation.cfm?id=16723]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を用意していました。&lt;br /&gt;
また広大なメモリ空間を必要としない組込み用途向けCPUにはMMUを持っていないものもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスは仮想アドレス空間にアクセスしています。&lt;br /&gt;
MMU がアドレス変換をして仮想アドレス空間より実メモリアドレス空間をマップしてくれています。&lt;br /&gt;
これによってプロセスが連続したメモリ空間を確保することができるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリに入りきらないものを外部記憶装置に書き出し、必要になったら実メモリに読み込もうというのが仮想記憶です。&lt;br /&gt;
実メモリアドレス空間より仮想アドレス空間よりが大きい状態になっていれば、実メモリ上にない仮想アドレスを要求することが発生します。&lt;br /&gt;
例えば32ビットアーキテクチャーの場合(2&amp;lt;sup&amp;gt;32&amp;lt;/sup&amp;gt; / 4GB  ) は仮想記憶空間として1048576(2&amp;lt;sup&amp;gt;20&amp;lt;/sup&amp;gt;)のページを持つことになります。&amp;lt;ref&amp;gt;IA-32アーキテクチャで物理アドレス拡張(PAE)を使うことはひとまずおいておきます。&amp;lt;/ref&amp;gt;もし512MBの物理メモリしか搭載していないマシンは内部で131072ページしか持っていません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
アクセス時はアドレス変換を行うためのキャッシュであるTLB (Translation Lookaside Buffer)にアドレスを問い合わせます。&lt;br /&gt;
MMUの中にTLBの機能が含まれているタイプ、あるいはCPUチップ上にMMUとは別にTLBを用意しているタイプなどがあります。&lt;br /&gt;
いずれにしてもTLBにアドレスが見つからなかった場合、つまり実メモリ上に該当ページを見つけられないとMMUはシグナルを発生させます。&lt;br /&gt;
これをページフォルトいいます。&lt;br /&gt;
&lt;br /&gt;
== ページング ==&lt;br /&gt;
=== ページフォルト === &lt;br /&gt;
[[File:Memory_fig3.png|thumb|right|300px|ページフォルト時のモデル]]&lt;br /&gt;
ページフォルト（Page Fault）の発生をうけてオペレーティングシステムは実メモリ上に必要な記憶領域を確保しようとします。&lt;br /&gt;
実メモリのサイズは限られているわけですから、&lt;br /&gt;
必要であれば実メモリのページ内容を外部記憶装置に書き出し、&lt;br /&gt;
空きを作りそこに新しいページをマッピングします。&lt;br /&gt;
再度、その外部に書き出されたページをアクセスすることが発生したら、&lt;br /&gt;
該当のページを外部記憶装置から実メモリ上に読み込んできます。&lt;br /&gt;
ページを読み込むのがページイン (page-in)、&lt;br /&gt;
ページを書き出すのはページアウト(page-out)といいます。&lt;br /&gt;
&lt;br /&gt;
=== スワップ === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
仮想記憶で実メモリ上からハードディスクなどの補助記憶装置との間でメモリの内容を書き出したり、読み込んだりするメカニズムことをスワップ(交換)といいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
厳密にいえば本来のスワップの定義はメモリが少なくなるとプロセスが使っているメモリをまるごと補助記憶装置に移動させる方法です。&lt;br /&gt;
ページングはページ単位ですからページングとスワップとは技術的には区別されます。&lt;br /&gt;
その意味でLinuxはページングだけやってスワップはしません。&amp;lt;ref&amp;gt; ちなみにソースコードmm/memory.cを見るとLinuxで仮想記憶が動き始めたのは1991年12月18日だそうです。mm/memory.c&amp;lt;/ref&amp;gt;&lt;br /&gt;
尚、 GNU/Linux 関連のドキュメントを読んでいると、&lt;br /&gt;
あまりスワップとページングの言葉の使い分けを明確に区別しているよう感じではなく、&lt;br /&gt;
仮想記憶でページング(paging)機能全体をざっくり指してスワップみたいな括りで呼んでいるような印象です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: 本来のスワップを持っているオペレーティングシステムには、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: スワップの具体的な運用に関する私見 [[スワップの運用について考えてみる]]&lt;br /&gt;
&lt;br /&gt;
=== Linuxのスワップ === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ですがLinuxはスワップという言葉を使っています。ここでは「ページをスワップ（交換）している」と解釈するしかないので、そういうことで話を進めます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、先ほど説明したように記憶空間はページと呼ばれる単位で分割されています。主記憶と補助記憶とのやりとりはページ単位で行われ、ページイン、ページアウトを行います。一般的にはハードディスク上にスワップ用のパーティションを取って、そこをスワップ先に指定します。多くの場合はインストール時にセットアップするようになっています。通常はパーティションをマウントするための情報を書く/etc/fstabにスワップパーティションの割り当ての記述が作られているはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  /dev/hda3 none  swap  sw,pri=0  0    0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
スワップの状態は/proc/swapsを見るとわかります。下の例はサイズが1453872K (1.45GB)バイトである/dev/hda3パーティションがスワップに使われているという意味です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cat /proc/swaps&lt;br /&gt;
 Filename       Type           Size    Used    Priority&lt;br /&gt;
 /dev/hda3      partition      1453872 0       -1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スワップ先はディスクパーティションだけではなく、通常のファイルでもスワップ先にできます。適当なサイズのファイルを作り、そのファイルをmkswapコマンドで処理し、最後にswaponコマンドでスワップに追加すると簡単に新しいスワップ領域が出来ます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== swapon ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばswapf01という名前のスワップファイルを作ってシステムにスワップファイルとして登録する時は次のようにします。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # /bin/dd if=/dev/zero of=swapf01 bs=8192 count=256&lt;br /&gt;
 # /sbin/mkswap swapf01 2048&lt;br /&gt;
 # sync &lt;br /&gt;
 # swapon swapf0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずswapf01を適当なサイズにして作成します。40KB以上、127MB以下ならいずれのサイズでも構いません。次に作ったファイルのサイズを1024で割った値をmkswapで指定するブロックサイズとします。mkswapが済んだならsyncしてからファイルをswaponします。ここではコマンドswaponを使っていますが、システムコールswapon()も用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どのファイルはハードディスクのパーティションであっても構いません。複数のハードディスクを同時に利用している時、スワップファイルを各々のハードディスク上に設定しスワップのプライオリティを同じ値にすることで、スワップディスクへの読み込み／書き込みなどディスクI/Oが分散させることができます。これはraid0のような効果となり高速化することになります。プライオリティを指定して、例えば高速なハードディスク、あるいはスワップファイルアクセス時にディスクスラッシングを避けるために作業しているハードディスクとは物理的に別のハードディスクをアクセスするようにするなどといったことも可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux 2.6.32でスワップについて試したことのメモランダム [[linuxのswapについて私が知っている二、三の事柄]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== zswap ====&lt;br /&gt;
&lt;br /&gt;
zswap[https://www.kernel.org/doc/Documentation/vm/zswap.txt]は、 Linux kernel version 3.15 から入った仮想メモリ圧縮 (Virtual Memory Compression)を利用したスワップで、外部記憶装置にページをスワップするのではなく、実メモリ上に作った圧縮ブロックデバイスにページをスワップする機能でです。実メモリ上にスワップできなくなった時に、これまでのスワップ機能で用意しているスワップ領域にスワップを始めます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ディスクなどメモリから比較すると低速なストレージへのI/Oが少なくなるため、頻繁にページアウトが発生しスワップファイルへのI/Oがボトルネックになるようなケースでは有用な機能です。フラッシュメモリを使ったSSDのような書き換え上限があるような外部記憶装置上にスワップファイルを作ると頻繁なスワップはメディアの劣化が進むためzswapが有効であるという議論もあります。圧縮処理が行われるため、その分、CPUに負荷がかかります。ただし、それがI/Oのオーバーヘッドによる処理の低下と比較し、相対的にどちらに利益があるかは、個々のシステム構成によって変化する議論であることは注意してください。&lt;br /&gt;
&lt;br /&gt;
== 局所参照性 ==&lt;br /&gt;
[[File:Memory_fig4.png|thumb|left|300px|キャッシュのモデル]]&lt;br /&gt;
&lt;br /&gt;
局所参照性とは「プログラムは同じ場所を繰り返しアクセスする性質を持ちやすい」というものです。&lt;br /&gt;
常に成立するわけではありません。&lt;br /&gt;
もしプログラムがランダムにメモリ空間全域をアクセスする性質を一般に持っていたならば、&lt;br /&gt;
たぶん仮想記憶のようなシステムは無意味だったでしょう。&lt;br /&gt;
なぜならば大量のページイン・ページアウトが発生しまうからです。&lt;br /&gt;
このように大量のページイン・ページアウトが発生してしまう状態をスラッシングと呼びます。&lt;br /&gt;
しかし殆んどのプログラムは局所参照性を持つので、&lt;br /&gt;
使われていない部分を外部に移しても全体としてみた場合、&lt;br /&gt;
リーズナブルなパフォーマンスが得られています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この考え方は仮想記憶に限らずCPUのキャッシュメモリなどでも使われています。&lt;br /&gt;
最近のCPUはキャッシュが512KB、1MB、2MB という具合にどんどん増えています。&lt;br /&gt;
これはメモリからデータをフェッチしてきて、CPU内のキャッシュにおき、そこをアクセスすることで高速化を狙います。&lt;br /&gt;
当然、外にあるメモリよりCPU内のキャッシュの方がアクセス速度は格段に良いですから、それだけ速度が出るということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これを一般化してみると、&lt;br /&gt;
「データを高速にアクセスできるほど装置は容量当たりのコストが高いので、&#039;&#039;&#039;容量とコストを勘案し多段に装置を組合せることによって、リーズナブルに高速で大容量のアクセスできる記憶装置を用意&#039;&#039;&#039;することができる」&lt;br /&gt;
ということがいえるでしょう。&lt;br /&gt;
メモリ、仮想記憶、ファイルシステムなど色々な場面でこの考え方が現れます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このアクセスが高速で小容量の装置と低速で大容量の装置との間でデータを移動させなければなりませんが、&lt;br /&gt;
この時どのデータを選ぶかが問題になってきます。&lt;br /&gt;
よく使われるデータは速い方へ、なかなか使われないデータは遅い方へ移すのが合理的です。&lt;br /&gt;
ただし、「良く使われる」というのは過去の話ではなく将来の話だという所がポイントです。&lt;br /&gt;
「良く使われるだろう」と判断するルールを決めなければなりません。&lt;br /&gt;
このルールでよく使われるのがLRU (least recently used)です。LRUは直訳すると「最近、最も使われていないもの」ということで、&lt;br /&gt;
簡単に言えば一番暇なものを入れ換えるという単純な話です。LinuxのページングもLRUのポリシーで行っています。&lt;br /&gt;
&lt;br /&gt;
== 動的なメモリ領域確保 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセス実行時に動的にメモリを確保するのにはプログラム中でmalloc(3)&amp;lt;ref&amp;gt; malloc(3)の3の意味はマニュアルの分類を示しています。&amp;lt;/ref&amp;gt;&lt;br /&gt;
を呼び出します。次のプログラムはプロセスが動的に512MBのメモリを割り当てるプログラムです。ここで使っているmalloc(3)やfree(3)の説明はオンラインマニュアルを参考してもらうとして、まずはプロセスが動的にメモリを確保するとどうなるかやってみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* プログラム: malloctest.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;C&#039; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int main()&lt;br /&gt;
{&lt;br /&gt;
  char *p;&lt;br /&gt;
  size_t  areasize=1024*1024*512;&lt;br /&gt;
  if ((p=(char *)malloc(areasize)) == NULL) {&lt;br /&gt;
    perror(&amp;quot;malloc&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  sleep(10);&lt;br /&gt;
  free(p);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*  実行例&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ cc malloctest.c &lt;br /&gt;
 ./a.out &amp;amp;&lt;br /&gt;
[1] 93627&lt;br /&gt;
$ ps -o user,pid,vsize,rss,cmd &lt;br /&gt;
USER         PID    VSZ   RSS CMD&lt;br /&gt;
hironobu   87439  10752  6392 bash&lt;br /&gt;
hironobu   93627 526788   580 ./a.out&lt;br /&gt;
hironobu   93628   9928  3440 ps -o user,pid,vsize,rss,cmd&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このプログラムは512MBメモリ領域をmalloc(3)を使いアロケーションしています。実行時の状況をpsで見てみると、VSZが526788、RSSが580となっています。VSZはVirtual memory Sizeのことで仮想記憶もふくめて全部のメモリサイズです。RSSはReal Set Sizeのことで、実メモリ(物理的なメモリ)で専有しているメモリサイズです。つまり、このプログラムは約527MBもの記憶領域を取っているにもかかわらず、実際の実メモリ上では580KBしか取られていません。 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: もしmallocが失敗した場合、malloc: xxxxというメッセージが出ます。その場合でも小さい数字にはなりますがVSZやRSSの値は出ているはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリ上にあるのは、現在使おうとしているメモリです。アクセスがまったく発生すらしていないページは、まだページインされていない状態と同じです。この初期状態の時はまだ何も存在していないので、ページアウトしたものをページインする動作にはなりません。ここの部分だけに着目すると、アクセス時には、そのまま実メモリに作られる形になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラム中のsleepのある行を除いて、コンパイルし実行すると見かけ上512MB以上ものメモリを消費するプログラムがであっても、一瞬でプログラムが終ります。なぜならば、512MBのメモリ空間にアクセスしていないので、見かけ上このサイズのメモリが取れていてもまだ存在していないからです。アクセスが発生した始めて実メモリ上に必要な領域が生成されます。このように大量のメモリを見かけ上確保しても、それを使わない限り仮想のままで終ります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次の ps コマンドを実行してみましょう。するとRSSでソートされて、USER / COMMAND / RSS / VSZの順で表示されます。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps -Ao user,args,rss,vsize --sort rss&lt;br /&gt;
 USER     COMMAND                        RSS   VSZ&lt;br /&gt;
 root     [keventd]                       0     0&lt;br /&gt;
 root     [ksoftirqd_CPU0]                0     0&lt;br /&gt;
 ...&lt;br /&gt;
 hironobu /usr/bin/emacs23            15732  42140&lt;br /&gt;
 hironobu gedit                       23204  173232&lt;br /&gt;
 hironobu /opt/google/chrome/chrome - 107380 359600&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
keventdやksoftirqd_CPU0などRSSとVSZが両方0のものはカーネルレベルで動いているスレッドです。ここではユーザレベルのプロセスであるemacs23のメモリの使い方に着目しましょう。emacs20はRSSは15732KBで、仮想記憶も含めたサイズは42140KBです。多くの場合、十分に実メモリに余裕があっても、プロセス中で生成された記憶空間がすべて実メモリの上に載っているわけではありません。必要のあるもののみ実メモリ上にページインされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
使われていない分、実メモリが空くわけですから、その分を動的にデバイスなどへのキャッシュなどに割り当ています。そのキャッシュが大きければ大きいほど、全体のパフォーマンスはよくなります。実メモリが必要になればキャッシュに使っていた実メモリをプロセスに回します。これはLinuxだけの話ではなく、今日多くのオペレーティングシステムではこのように全体のパフォーマンスを上げるためにメモリを効率よく使うというメカニズムが取り込まれています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: vmstatで観察してみましょう。vmstatは仮想記憶のステータス観察するためのツールです。1秒毎に表示するオプションで動作させながら、先程のプログラムを改造し徐々に記憶を取るようなプログラムにして動かし、観察してみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % vmstat  1 &amp;lt;- 1秒毎に表示&lt;br /&gt;
  procs                  memory    swap        io    system         cpu&lt;br /&gt;
  r b w  swpd  free  buff cache  si  so   bi   bo   in   cs  us  sy  id&lt;br /&gt;
  0 0 0   624  3324 14868 61228   0   0    1    1    3    9   0   0   0&lt;br /&gt;
 ......&lt;br /&gt;
  4 0 0 28724  1120   412  2196 476 536  119  160  444  668  93   7   0&lt;br /&gt;
  2 1 0 29964  1140   368  2128 316 124   79  310  485  817  37   9  54&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== コピーオンライトとその実際 == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのカーネルではプロセスが親から引き継がれたメモリ領域や実行コードなどを引き継いでいても、そこに書き換えが発生するまで、実際のメモリ領域はとりません。書き込みがあって始めてメモリ領域を確保し、中身をコピーして別なものにします。このことをコピーオンライト(CoW: Copy on Write)といいます。このような仕組みにより、高速に新しいプロセスを生成したり、あるいはメモリの効率的な利用が出きるようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/proc/(プロセスid)/smapsは、カーネル内の該当プロセスのメモリ利用状況を表示するAPIです。それを使って実験したいと思います。&lt;br /&gt;
dashはDebian版軽量シェルでシステムのシェルスクリプトを実行するのに使われます。&lt;br /&gt;
さて、$$はシェル自身のプロセスidですので、/proc/$$/smapsとすると現在使っているシェルのメモリ利用状況がわかります。&lt;br /&gt;
注目するのは Shared_Clean と Private_Clean の値です。&lt;br /&gt;
Shared_Clean はシェアしているメモリです。&lt;br /&gt;
Private_Clean は自らのメモリです。&lt;br /&gt;
クリーンな、という意味は、まだそのページは変更されていない（書き込みがおこっていない）という意味です。&lt;br /&gt;
まず最初、dashを起動してdashシェル環境でメモリ利用状況をみます。&lt;br /&gt;
この時、引き継ぐものがないのでPrivate_Cleanが76kB (= Rssの値と同じ)、Shared_Cleanが0kBとなっています。&lt;br /&gt;
次にdashの中でさらにdashを起動します。つまり最初のdashが親プロセスとなった新しいdashです。&lt;br /&gt;
この上で両方の値をみるとPrivate_Cleanが0kB、Shared_Cleanが76kB(= Rssの値と同じ)となっています。&lt;br /&gt;
つまり、子プロセス側となったdashのメモリは、この時点ではシェアしているものを使っていることがわかります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ dash&lt;br /&gt;
 $ cat /proc/$$/smaps | head -9&lt;br /&gt;
 08048000-08060000 r-xp 00000000 08:01 4825       /bin/dash&lt;br /&gt;
 Size:                 96 kB&lt;br /&gt;
 Rss:                  76 kB&lt;br /&gt;
 Pss:                  76 kB&lt;br /&gt;
 Shared_Clean:          0 kB&lt;br /&gt;
 Shared_Dirty:          0 kB&lt;br /&gt;
 Private_Clean:        76 kB&lt;br /&gt;
 Private_Dirty:         0 kB&lt;br /&gt;
 Referenced:           76 kB&lt;br /&gt;
 $ dash&lt;br /&gt;
 $ cat /proc/$$/smaps | head -9&lt;br /&gt;
 08048000-08060000 r-xp 00000000 08:01 4825       /bin/dash&lt;br /&gt;
 Size:                 96 kB&lt;br /&gt;
 Rss:                  76 kB&lt;br /&gt;
 Pss:                  34 kB&lt;br /&gt;
 Shared_Clean:         76 kB&lt;br /&gt;
 Shared_Dirty:          0 kB&lt;br /&gt;
 Private_Clean:         0 kB&lt;br /&gt;
 Private_Dirty:         0 kB&lt;br /&gt;
 Referenced:           76 kB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mmap ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mmap(2)はファイルをメモリのように使うためのシステムコールです。mmapを使うことによってファイルとメモリの境目はなくなります。次のプログラムを見てください。これはファイルをオープンした後、ファイルの中身を文字型配列としてアクセスしています。readを使って読み込みをしているわけではありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* プログラムmmap.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;C&#039; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/mman.h&amp;gt;&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct stat st;&lt;br /&gt;
  char *p;&lt;br /&gt;
  int i;&lt;br /&gt;
  fd=open(&amp;quot;dat&amp;quot;,O_RDWR);&lt;br /&gt;
  fstat(fd, &amp;amp;st);&lt;br /&gt;
  p=mmap(0,st.st_size,(PROT_READ|PROT_WRITE),MAP_PRIVATE,fd,0);&lt;br /&gt;
  for(i=0; i &amp;lt; st.st_size; i++) {&lt;br /&gt;
    printf(&amp;quot;[%c]&amp;quot;,p[i]);&lt;br /&gt;
  }&lt;br /&gt;
  close(fd);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*  実行&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ echo -n &#039;abcdefg&#039; &amp;gt; dat&lt;br /&gt;
 $ cc mmap.c&lt;br /&gt;
 $ ./a.out&lt;br /&gt;
 [a][b][c][d][e][f][g]$ &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイルdatの中身は&amp;quot;abcdefg&amp;quot;となっています。datをオープンしfstatでファイルのステータス情報を取り出します。そのステータス情報の中のファイルサイズがst.st_sizeです。mmapを使って、ファイルdatの中身をメモリ空間として割り当てます。そのポインタがpです。ループ内でpの中身を表示させると、ファイルの内容と同じであることがわかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはメモリの中にファイルを読み込んでいるわけではありません。ファイルをメモリにマップしたのです。スワップページからページインするのと良く似ていると気が着く人もいるでしょうが、基本的には同じ動作で、ファイルを読み出す過程はページインと同じ仕組みです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これは今日のUNIX系オペレーティングシステムでの重要なメカニズムの一つです。たとえばLinuxではプログラムを実行する時、バイナリの実行ファイルや標準ライブラリを読み込む動作をするのではなくmmapでマップします。これでファイルシステムとは違う記憶領域であるはずのメモリ内に存在するのと、まったく同じ動作ができます。動作時に実行コードをページインします。&lt;br /&gt;
&lt;br /&gt;
glibcでのmalloc実装は/dev/zeroをオープンし一定領域をmmapで確保し、その領域から必要な分を切り出してプログラム側に返却しています。つまりmallocを呼び出したプログラムは/dev/zeroの領域を使っています。/dev/zeroは物理的なデバイスの実体を持たないので、カーネルが与えたメモリ空間になります。mmapはこんな使い方もされているという一例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、この例題プログラムではマップする属性をMAP_PRIVATEとしているので、ファイルの内容を読み込みはしますが、メモリ領域に書き込んでも、それはファイルには書き込まれません。これをMAP_SHAREDとするとファイルと同期を取ることができます。このファイルを複数のプログラムからオープンすると共有メモリとして利用できます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 内容をアップデートして同期するにはメモリに書き込み後、msync(2)やmunmap(2)を呼ぶことが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 単一レベル記憶 ===&lt;br /&gt;
&lt;br /&gt;
ファイルもメモリも、さらにデバイスすらも単純な1つの記憶空間として扱おうというコンセプトが単一レベル記憶です。&lt;br /&gt;
現在、オペレーティングシステムレベルでサポートしているのはIBM社のSystem iシリーズ&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
IBMのサイトにあるIBM System iの単一レベル記憶の解説 :  http://www-06.ibm.com/systems/jp/i/seminar/reconf/reconf1.shtml&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ぐらいしかないので、&lt;br /&gt;
インターネット上で説明を探すとIBM System iの機能＝単一レベル記憶の定義みたいな説明しかありませんが、&lt;br /&gt;
実は、その歴史は古く1960年代に作られたMultics上に既に実装&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Multics and More VM&lt;br /&gt;
https://users.cs.duke.edu/~chase/cps210-archive/slides/multics-vm.pdf&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXは単一レベル記憶を前提としているデザインはありませんが、現在のUNIX系のオペレーティングシステムはmmapを実装することによってファイルもメモリも、そしてデバイスも同様に扱うことができる利益を得ています。&lt;br /&gt;
例としては今時のLinuxやその他UNIX系のオペレーティングシステムでは実行バイナリやライブラリを動かすとき、一々ファイルの中身を読み込む動作をせず、実行するバイナリデータを内部でマップしてしまいます。&lt;br /&gt;
ですから古典的なUNIXで言われるような、「実行バイナリファイルをメモリに読み込み実行する」という表現は、少なくとも現在のLinuxの実行時の表現としては適切ではないという状況になっています。あとデバイスの利用例としては、malloc()のいくつかの実装&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
The GNU Allocator&lt;br /&gt;
https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
では内部で記憶領域を確保するとき/dev/zeroをmmapでオープンして使っています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1729</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1729"/>
		<updated>2022-08-18T18:55:14Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* プライオリティ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  GNU/Linux上で円周率の計算をおこなう http://h2np.net/pi/&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下3300万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、数十分、あるいは数時間という具合に長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;追記: その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、&lt;br /&gt;
あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が低く、大きいものが実行優先順位が高くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1728</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1728"/>
		<updated>2022-08-18T17:59:56Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 使えるスケジューリングを調べてみる */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  GNU/Linux上で円周率の計算をおこなう http://h2np.net/pi/&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下3300万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、数十分、あるいは数時間という具合に長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;追記: その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、&lt;br /&gt;
あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が高く、大きいものが実行優先順位が低くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1727</id>
		<title>プロセス管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E7%AE%A1%E7%90%86&amp;diff=1727"/>
		<updated>2022-08-18T17:31:54Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* スレッド */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== プロセスの基本的概念 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラムが動作する実行実体のことをプロセスと呼びます。単純化して説明すると、プログラムの実行のことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。&lt;br /&gt;
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。&lt;br /&gt;
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかります。&lt;br /&gt;
カーネルの[https://github.com/torvalds/linux/blob/master/include/linux/threads.h ソースコード]内ではプロセスIDの最大値は次のようにして設定しています。&lt;br /&gt;
最少構成でカーネルを作った場合は4096、32ビットCPUだと32768、64ビットもしくはそれ以上のCPUだと4 * 1024 * 1024つまり4194304ということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * This controls the default maximum pid allocated to a process&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
 * A maximum of 4 million PIDs should be enough for a while.&lt;br /&gt;
 * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]&lt;br /&gt;
 */&lt;br /&gt;
#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \&lt;br /&gt;
        (sizeof(long) &amp;gt; 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
概念的にどのような位置づけなのかを確認してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではリソース(計算資源)という視点から説明してみます。&lt;br /&gt;
プログラムが実行する際のいろいろなリソースの1つとして、CPUリソースがありますが、&lt;br /&gt;
まずそのCPUリソースで考えてみましょう。円周率π&lt;br /&gt;
&amp;lt;ref&amp;gt;  GNU/Linux上で円周率の計算をおこなう http://h2np.net/pi/&amp;lt;/ref&amp;gt;&lt;br /&gt;
を小数点以下3300万桁まで求めるプログラムがここにあるとします。&lt;br /&gt;
このπを求めるには、数分、数十分、あるいは数時間という具合に長いCPU実行時間が必要です。&lt;br /&gt;
これを動かしたとしましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ユーザ側から見る ==== &lt;br /&gt;
[[File:Program-cpu.png|thumb|right|300px|プログラムは自分専用CPUを持っているように見える]]&lt;br /&gt;
&lt;br /&gt;
ユーザ側の視点から見てみましょう。&lt;br /&gt;
CPUを1つしか搭載していないシステム上でユーザがπを求めるプログラムを3つ同時に動かした&lt;br /&gt;
&amp;lt;ref&amp;gt;同じ答えを３つも必要ないというツッコミはここではなし。&amp;lt;/ref&amp;gt;&lt;br /&gt;
とします。もちろん遅いでしょうが計算は3つ同時に動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 話を単純化するために、ここではマルチコアとかハイパースレティングなどの能力も持っていない単純な1つの計算ユニットだけあるCPUとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これをプログラム側の視点から見てみましょう。&lt;br /&gt;
この時、πを求めている各々のプログラムは、他にどんなプログラムが同時に動作しているのか意識することはありません。&lt;br /&gt;
プロセスは自分専用のCPUを持っているように見えています。&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
&lt;br /&gt;
もう一度ユーザ側視点に戻って、この状態を見てみると、&lt;br /&gt;
仮想的なリソースとしてのCPUリソースはプログラムに割り当てられ、&lt;br /&gt;
使っているユーザは同時に3つのプログラムが並行して動いているように見えます。&lt;br /&gt;
&lt;br /&gt;
==== カーネル側から見る ==== &lt;br /&gt;
&lt;br /&gt;
[[File:Process-resource.png|thumb|right|350px|プロセスは色々なリソースを持っている]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今度はカーネル側から見てみましょう。物理的なCPUが1個しかありません。&lt;br /&gt;
ですから、まったく同時に複数のプログラムが処理できているわけではありません。&lt;br /&gt;
ある一瞬においては1つの物理的なCPUを専有できるのは1つのプログラムだけです。&lt;br /&gt;
また、その実行のためにCPUリソース以外にも必要なリソースも割り当てられています。&lt;br /&gt;
実行中プロセスの持つリソースを分類すると次のようになります。&lt;br /&gt;
* CPUリソース (タスク系リソース)&lt;br /&gt;
* プロセス間通信系リソース&lt;br /&gt;
* 記憶管理系リソース&lt;br /&gt;
* ファイル管理系リソース&lt;br /&gt;
* ユーザ管理系リソース&lt;br /&gt;
* ほか&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらの割り当てられたリソースを使って実行する主体をプロセスと呼ぶことができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:個々のプロセスのデータ構造は[https://github.com/torvalds/linux/blob/master/include/linux/sched.h sched.h]に定義されている[https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L723  struct task_struct]です。個々のプロセスが保持する情報(とリソース)にはどのようなものがあるかチェックしてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実行するために必要なリソースを個々のプログラム実行に割り当てて、実行単位プロセスの説明を試みました。&lt;br /&gt;
さて、今度はプロセスを実際にCPUに割り当てていくことを考えてみましょう。&lt;br /&gt;
プロセスを割り当てるためにスケジュール（予定）を立て処理を進めていく必要があります。&lt;br /&gt;
それがスケジューリングです。&lt;br /&gt;
スケジューリングを説明するまえに、もう少しプロセスをみてみましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセス・タスク・スレッド === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここまでの説明では実行実体の単位のことをプロセスと呼んでいますが、これは今時のUNIXから見て古典的な実行単位です。&lt;br /&gt;
今は、タスクとスレッドという単位で実行単位を考えるようになっています。タスク・スレッド・プロセスを定義をすると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* スレッド実行に必要なすべてのリソースのすべてを指してタスク&lt;br /&gt;
&lt;br /&gt;
* リソース中でCPUリソースとして処理の流れを作るものをスレッド&lt;br /&gt;
&lt;br /&gt;
* １つのタスクに１つのスレッドしかないものをプロセス&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スレッドやタスクの考え方（と、実装）は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。&lt;br /&gt;
80年代に入ってから色々な組織がスレッドの実装を試みました。&lt;br /&gt;
米ブラウン大学の [https://cs.brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、&lt;br /&gt;
サンマイクロシステムズのLWP (Light-weight process)、DECのDECthreads、&lt;br /&gt;
[https://kilthub.cmu.edu/articles/journal_contribution/C_threads/6603980/1 CMUのCスレッドパッケージ]&lt;br /&gt;
がありました。各々互換性はありません。&lt;br /&gt;
紆余曲折あり、現在では&lt;br /&gt;
[https://hpc-tutorials.llnl.gov/posix/ POSIX仕様のスレッド]である&lt;br /&gt;
[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]&lt;br /&gt;
が主流になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タスクが1つのスレッドしか持たない時、これはUNIX の伝統的な実行実体のプロセスです。&lt;br /&gt;
ですから、単純にプロセスと呼んでも構わないですし、&lt;br /&gt;
また同時に（ここまでの説明の範囲では）「プロセス＝タスクのこと」と考えてもかまいません。&lt;br /&gt;
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、&lt;br /&gt;
スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。&lt;br /&gt;
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。&lt;br /&gt;
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、&lt;br /&gt;
これから先はプロセスという言葉は廃れてタスクという言い方が主流になるかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 複数のプロセスが動くことをマルチタスクと呼びます。なんでマルチプロセスではないのかというと60年代に最初にマルチタスクが出来たオペレーティングシステムでは実行実体の単位をタスクと呼んでいたからです。なのでマルチタスクと呼びます。タスクという用語は使われる場面で微妙に意味が違うので注意しましょう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
[[File:Process-flow.png|thumb|right|480px|プロセス・ステータスの流れ]]&lt;br /&gt;
オペレーティングシステムは実行すべき、たくさんのプロセスを同時に抱え込んでいるわけですが、それよりも少ない数のCPUでどうにかこうにか、やりくりしなければいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずプロセスの状態に着目して、その動きを見てみましょう。&lt;br /&gt;
その前にLinuxのタスクの状態遷移を細かく追っていくと、初心者にとって処理の流れの全体像がわかりづらくなると思います。&lt;br /&gt;
そこでここでは説明は理解しやすいようにLinuxそのままではなく&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
LinuxカーネルではTASK_RUNNING、TASK_INTERRUPTIBLE、 TASK_UNINTERRUPTIBLE、 TASK_STOPPEDなどの状態をもちます。詳しくはヘッダファイルの [https://github.com/torvalds/linux/blob/master/include/linux/sched.h#L82 sched.h] を参照してください。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ある程度単純化したプロセス状態の基本モデルを考えて説明したいと思います。&lt;br /&gt;
さて、次の6つの状態を持つモデルを考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* (1) 実行中(RUNNING): プロセスがCPUを使用し実行している状態&lt;br /&gt;
&lt;br /&gt;
* (2) 待機中(READY):  いつでも実行できるが、他のプロセスがCPUを使っているので待機している状態&lt;br /&gt;
&lt;br /&gt;
* (3) イベント待ち(SLEEP): 入力などのイベントを待ている状態&lt;br /&gt;
**  INTERRUPTIBLE: 割込みなどによって待ち状態が解除される &lt;br /&gt;
**  UNINTERRUPTIBLE: 解除されない限りSLEEP状態になっている&lt;br /&gt;
&lt;br /&gt;
* (4) 新しいプロセス生成(NEW): 新しいプロセスを作る状態&lt;br /&gt;
&lt;br /&gt;
* (5) 終了待ち (ZOMBIE) : プロセスの終了処理を待っている状態&lt;br /&gt;
&lt;br /&gt;
* (6) 停止 (STOPPED) :  プログラムを一時的に停止させている状態&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もっと単純に「待機中」「イベント待ち」「実行中」の３つの間を遷移するモデルにしましょう。動きは次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 実行中→待機中 : 割り当てられたCPUリソースを使ったので、CPUでの実行状態から待機状態になる。この時、CPUリソースが使える状態になれば、すぐに実行状態に戻れる。&lt;br /&gt;
&lt;br /&gt;
* 待機中→実行中 : すぐにでも実行を行える状態で待っていて、CPUが割り当てられればすぐに実行中になる。&lt;br /&gt;
&lt;br /&gt;
* 実行中→イベント待ち : 入力などのイベントのために待ち状態になっている。&lt;br /&gt;
&lt;br /&gt;
* イベント待ち→待機中 : 入力のようなイベントがあったので待機中になっている。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて先程例に出したπの計算をしている同時に3つ動かしているプログラムは、ほとんどの場合、「実行中→待機中」と「待機中→実行中」をいったり来たりしているはずです。&lt;br /&gt;
たまにIOのためにイベント待ちの状態になりますが、それよりもはるかにCPUを使いπの計算している時間の方が多いはずです。&lt;br /&gt;
待機中(READY状態)のプロセス数を示すロードアベレージは1.0を越えて徐々に増えていき最後には3.0を越えるはずです。&lt;br /&gt;
一方で例えばエディタのようなインタラクティブなプログラムを考えてみます。そうなると、ユーザが実際に使っている時間のほとんどは入力を待っている待機中です。ロードアベレージは1.0以下で限りなく0.0に近くなるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの状態 ===&lt;br /&gt;
&lt;br /&gt;
皆さんが動かしているデスクトップレベルでは、いつもそんなに激しく色々なプロセスが同時にCPUを奪いあっている状態ではありません。動いているプロセスのほとんどは入力を待つSPLEEP状態です。コマンドtopを使ってプロセスの状況を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % top&lt;br /&gt;
  18:49:03 up 49 days,  4:38,  8 users,  load average: 2.00, 0.82, 0.31&lt;br /&gt;
 80 processes: 75 sleeping, 5 running, 0 zombie, 0 stopped&lt;br /&gt;
 CPU states:  98.0% user,   2.0% system,   0.0% nice,   0.0% idle&lt;br /&gt;
 Mem:    645016K total,   622120K used,    22896K free,    46656K buffers&lt;br /&gt;
 Swap:  2441704K total,    16192K used,  2425512K free,   159200K cached&lt;br /&gt;
   PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
  6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
  6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
  6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
 19707 hironobu   9   0  5128 5128  2336 S     0.3  0.7   2:38 sawfish&lt;br /&gt;
 13399 hironobu  11   0  1060 1060   820 R     0.3  0.1   0:03 top&lt;br /&gt;
 13398 hironobu   9   0  3024 3024  1932 R     0.1  0.4   0:01 xterm&lt;br /&gt;
     1 root       8   0   472  432   412 S     0.0  0.0   0:43 init&lt;br /&gt;
     2 root       9   0     0    0     0 SW    0.0  0.0   0:00 keventd&lt;br /&gt;
     3 root      19  19     0    0     0 SWN   0.0  0.0   0:00 ksoftirqd_CPU0&lt;br /&gt;
&amp;lt;/PRE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコンピュータでは現在80プロセスが動いていて、待機中75、実行中5、終了待ち0、ストップ0です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
STATの部分はプロセスの状態を表しています。一文字目がプロセスの状態を示していています。&lt;br /&gt;
&lt;br /&gt;
* R : RUNNING状態 (実行している、あるいは実行待ちの状態）&lt;br /&gt;
* S : SLEEP状態 (I/O待ちなどの状態)&lt;br /&gt;
* D : 割込みが利かないSLEEP状態 (sleep関数を呼んでSLEEPしている状態など）&lt;br /&gt;
* Z : ゾンビ状態 (終了したがまだ親プロセスが終了処理を終えていない状態）&lt;br /&gt;
* T : ストップ状態 (Control-Z/SIGSTOPによるプロセス停止の状態)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
イベント待ちSLEEP状態で入力などの割込みで止まっている場合はSのSLEEP状態として表示されますが、bashやcsh のようなジョブコントロールが可能なシェル上でコマンドを実行し、コントロールZで止めたような場合はストップ状態となりTのストップ状態として表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ほとんどのSLEEP状態は場合は割込みがあればすぐに動き出すINTERRUPTIBLEなタイプです。カーネル中で解除されない限りSLEEP状態を続ける UNITERRUPTIBLE のような状態はデバイスをロックするなど特別な場合に使われるだけで、あまり多くはありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:プロセスの状態を表しているSTATの欄をみるとR/S/D/Z/Tの後ろにさらに文字がついていますがこの意味は何でしょうか? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
πの計算のように数値計算を延々と行うプログラムは別として、ディスクトップで利用しているソフトウェアの多くはユーザからのインタラクション(入力)待ちの状態で止まっているようなものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばコンパイラがソースコードをコンパイルするプロセスでも実行中、待機中、イベント待ち状態を遷移します。&lt;br /&gt;
なぜならばコンパイラは、ファイル入出力を発生させるので、その入出力が発生している最中はイベント待ち状態になっています。ファイル入出力に10msかかったとして、その間はCPUは遊んでいる状態になります。&lt;br /&gt;
10msというは今日のCPUにとっては、長い長い暇な時間で、かなり大量の計算ができます。&lt;br /&gt;
このようにプロセスがCPU専有時間が過ぎたので次のプロセスに順番を与える以外にも、他のプロセスがCPUを使う状態が数多く発生します。&lt;br /&gt;
&lt;br /&gt;
=== プロセスの生成 ===&lt;br /&gt;
&lt;br /&gt;
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。&lt;br /&gt;
&lt;br /&gt;
==== fork(2)  ====&lt;br /&gt;
プロセスの生成は[http://man7.org/linux/man-pages/man2/fork.2.html fork(2)]を使い親プロセスが子プロセスを生み出します。下のコードを見て下さい。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
int  main(void){&lt;br /&gt;
  pid_t pid, wait_pid;&lt;br /&gt;
  int wait_stat;&lt;br /&gt;
  if ( (pid = fork()) == 0 ) {&lt;br /&gt;
    sleep(3);&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in child: %d\n&amp;quot;,pid);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  else {&lt;br /&gt;
    if ( pid == -1 ) {&lt;br /&gt;
      exit(EXIT_FAILURE);&lt;br /&gt;
    }&lt;br /&gt;
    fprintf(stderr,&amp;quot;pid in parent: %d\n&amp;quot;,pid);&lt;br /&gt;
    wait_pid=wait(&amp;amp;wait_stat);&lt;br /&gt;
    fprintf(stderr,&amp;quot;wait returns : %d(%o)\n&amp;quot;,wait_pid,wait_stat);&lt;br /&gt;
    exit(EXIT_SUCCESS);&lt;br /&gt;
  }&lt;br /&gt;
  return(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre &amp;gt;&lt;br /&gt;
&lt;br /&gt;
システムコールfork(2)はフォーク後、親プロセスでは子プロセスのプロセスIDを返却し、子プロセスでは0を返却します。&lt;br /&gt;
またフォークができない時は-1を返却します。&lt;br /&gt;
wait(2)は子プロセスの終了を待つシステムコールです。&lt;br /&gt;
このプログラムを実行すると次のような出力になります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ./a.out &lt;br /&gt;
 pid in parent: 5008&lt;br /&gt;
 pid in child: 0&lt;br /&gt;
 wait returns : 5008(0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初は1つのプロセスですが、システムコールfork()を呼び出した時点で、エラーが発生しない限り2つのプロセス、つまり親と子のプロセスになります。&lt;br /&gt;
子プロセスは親プロセスのコピーで、そのまま子プロセス側の処理を行いますがsleep()があるので一旦スリープします。&lt;br /&gt;
親プロセスはそのまま続行していますから（そしてsleepしていませんから）、&amp;quot;pid in parent : ~ &amp;quot;を出力します。&lt;br /&gt;
システムコールwait()は子プロセスの終了を待つ機能です。そして、まだ子プロセスは終了していませんから、子プロセスの終了を待ちます。&lt;br /&gt;
子プロセスはsleepの待ち時間が過ぎれば&amp;quot;pid in child:~&amp;quot;を出力して終了します。&lt;br /&gt;
親プロセスでは子プロセスが終了したのでwaitが終了した子プロセスのidを返却します。&lt;br /&gt;
親プロセスは&amp;quot;wait returns : ~&amp;quot;を出力して終了します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
新しいコマンドを動かすのもforkを使い子プロセスを生成します。具体的には子プロセスが新しい実行ファイルを動かすにはシステムコールexecve(2)使います。これは、子プロセスの資源を新しい実行ファイルの資源として与えるものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  プログラム中ではシステムコールexecve(2)よりも下のサンプルコードのようにライブラリ関数execl(3)などを使う場合の方が多いでしょう。下のコードはライブラリ関数execl(3)を使って/bin/dateを実行している例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
void main(void) {&lt;br /&gt;
  int wstat;&lt;br /&gt;
  if ( fork() == 0 ) {&lt;br /&gt;
    execl(&amp;quot;/bin/date&amp;quot;,&amp;quot;/bin/date&amp;quot;,NULL);&lt;br /&gt;
  }&lt;br /&gt;
  wait(&amp;amp;wstat);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: カーネルの中でforkをするのは[https://github.com/torvalds/linux/blob/master/kernel/fork.c#L2541  kernel_clone()]です。それまでは_do_fork()でしたが2020年にリリースされたLinux Kernel 5.9以降kernel_clone()になりました。[https://patchwork.kernel.org/project/linux-kselftest/cover/20200818173411.404104-1-christian.brauner@ubuntu.com/#23554325 参考資料]&lt;br /&gt;
&lt;br /&gt;
==== プロセスを生成するシステムコール ====&lt;br /&gt;
&lt;br /&gt;
プロセスを生成するシステムコールにはfork(2)の他にvfork(2)、さらにLinuxではclone(2)があります。vfork(2)の違いは親プロセスからページテーブルをコピーすることなく子プロセスを生成することです。子プロセスでexecve(2) が実行されれば、親プロセスからコピーされたページテーブルの内容は子プロセスの内容に変わります。つまり、fork(2)後すぐにexecve(2)が呼び出されるような場合、使われない内容をわざわざコピーする時間が短縮する分パフォーマンスが改善できます。&lt;br /&gt;
&lt;br /&gt;
fork(2)とclone(2)ともに新しい子プロセスを生成しますが、fork(2)が内容をコピーするのに対しclone(2)は内容を共有しています。その意味では後に説明するスレッドと同じです。execve(2)で新しい内容を必要とした時に始めてコピーを行います。ですからvfork(2)はclone(2) の変形版といえます。ただしclone(2)はLinux独自のものなので、プログラムに使うと、他のシステムへの移植の際は問題が発生する可能性があります。&lt;br /&gt;
&lt;br /&gt;
==== プロセスを殺すシステムコール ====&lt;br /&gt;
&lt;br /&gt;
その反対にプロセスを殺すシステムコールはkill(2)です。ここでは内部でkill(2)を呼んでいるコマンドkillを紹介しましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ kill -9 8321&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
killにプロセスIDを与えた場合、そのプロセス番号にSIGKILLを送ります。SIGKILLはプロセスを殺すシグナルです。killに与えるプロセスIDが0の場合、自分自身を殺します。-1は、シグナルを受け取ることができる全てのプロセスに送られます。プロセスinitはプロセスIDが1で、むかしは1を指定するとシステム全体が死んでいたのですが、今はルート権限でkill -9 1としても死なないようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: killでマイナスの値を指定することができます。それはどのような役目をするのでしょうか？&lt;br /&gt;
&lt;br /&gt;
===  スケジューリング ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスにCPU資源をどのように与えるかの順番を決めるスケジュール (schedule)ことを行うことがスケジューリング(scheduling)です。それを司るのがスケジューラ(scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Linux Scheduler&lt;br /&gt;
https://www.kernel.org/doc/html/latest/scheduler/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
==== 基本的なスケジューリング方式 ====&lt;br /&gt;
&lt;br /&gt;
スケジューリングの方式にはポリシーと呼ばれる、いくつかの方式&amp;lt;ref&amp;gt;Linux カーネル version 3.14 以降ではデッドラインスケジューリングポリシー (SCHED_DEADLINE) が追加されています。&amp;lt;/ref&amp;gt;があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 独自優先順位 ( SCHED_OTHER ) :  実行に使用した時間の違いなどにより優先順位をつけるなどし、その優先順位に従って割り当てる方式。(Linuxデフォルト)&lt;br /&gt;
&lt;br /&gt;
* FIFO ( SCHED_FIFO ) : 最初に入ったプロセスが終了するまでそのプロセスが専有する方式。最初に入ったものが最初に出るのでFirst-In-First-Out / FIFOと呼ばれる。&lt;br /&gt;
&lt;br /&gt;
* RR ( SCHED_RR ) : ラウンドロビン( Round Robin: 一定の間隔で順繰りに回ってくる)でプロセスが割り当てられる方式。&lt;br /&gt;
&lt;br /&gt;
* バッチ ( SCHED_BATCH ):  （たとえば大量の処理をしても）プライオリティの変化をつけない。尚、当然ながらタイムシェアリングシステムにおいてのバッチという意味である。&lt;br /&gt;
&lt;br /&gt;
* アイドル ( SCHED_IDLE ):   CPUがアイドリング状態になった時に処理が行われる。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
独自優先順位は、何らかの評価方式でCPUに割り当てる優先度や割り当てる時間を決めて順番を決める方式です。何らかという通り、色々な方法があって、オペレーティングシステムの違いによって異なりますし、あるいは同じカーネルであってもバージョンの違いによっても異なります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FIFOの場合、そのプロセスがCPUを専有するのでCPUが空かない限り他のプロセスはCPUは割り当てられません。プロセスがSLEEP状態から復帰した場合、次にCPUを割り当てられるのはFIFOプロセスです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう:  FIFOでプロセスを動かすとリアルタイム処理性能は満足するのでしょうか?もし足らないものがあるとすると、それは何でしょうか?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ラウンドロビンは一定時間CPU時間を消化したプロセスを待ち状態に戻し、待っていた次のプロセスに切替えて順繰りにプロセスを実行していく方法です。この一定時間のことをタイムスライス(Time Slice)あるいはタイムクアンタム (Time Quantum)と呼びます。公平にプロセスにCPUを割り当てることになります。タイムスライスを小さくすれば小さくするのど、細かくプロセスをCPUへ割り当てることができますが、しかし割り当て処理の回数が増えるにつれカーネル自体が消費するCPU時間も多くなっていきます。ですから、リーズナブルな値にしなければなりません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  筆者の知る範囲ではラウンドロビン方式と優先順位づけなどを併用しているので、単純に順番を待つだけのラウンドロビン方式というのを見たことがありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux (Kernel 4.4.0で確認)でのバッチ ( SCHED_BATCH ) とアイドル ( SCHED_IDLE ) を実行した時の違いは曖昧です。カーネルの中では扱いが違いますが、どちらとも同じく実行優先度の各種パラメータが同様に低く押さえられており、処理時間の結果をみると両者の区別をつけるのはむずかしいといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxの基本はUNIXの流れであるラウンドロビンと優先順位をミックスしたものです。優先順位によってタスク待ちの優先順位の高いキューにセットされます。またそれだけでもなくタイムスライスの値も変化させています。Linux 2.6.22の場合、タイムスライスは平均100msですが内部では最小5msから最大800msまで内部で動的に変化させています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linux 2.6系におけるスケジューラは以前2.4系で使われていたスケジューラからみると画期的に性能がいいO(1)スケジューラ(Order one scheduler)に変更されました。さらにLinux 2.6.23からO(1)スケジューラからCFS(Completely Fair Scheduler)に変更されました。&lt;br /&gt;
&lt;br /&gt;
==== 使えるスケジューリングを調べてみる ====&lt;br /&gt;
&lt;br /&gt;
その後 Linux 3.14 (2014/3/20リリース) からリアルタイム指向の処理に必要なデットラインを処理するための [https://core.ac.uk/download/pdf/14699805.pdf SCHED_DEADLINE] がスケジューラ &amp;lt;ref&amp;gt; デフォルトで使えるかどうかはディストリビューションによります。&amp;lt;/ref&amp;gt; に加わっています。Linux 3.14ではデットライン・スケジューラのアルゴリズムはEarliest Deadline First (EDF)を採用していましたが、Linux 4.13 (2017/9/5リリース)からはEDFを改良しさらに Constant Bandwidth Server ( CBS ) 加えた( と、 [https://github.com/torvalds/linux/blob/master/kernel/sched/deadline.c カーネルのコメント] では表現している ）アルゴリズムを採用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
カーネルにどのスケジューラを入れるかはディストリビューションによって異なりますし、またカーネルのバージョンによっても違ってきます。どのようなスケジューリングが可能かを簡単に調べるのにはコマンド [[chrt]] が便利です。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ uname -r&lt;br /&gt;
4.4.0-134-generic&lt;br /&gt;
$ sudo chrt -m&lt;br /&gt;
SCHED_OTHER min/max priority	: 0/0&lt;br /&gt;
SCHED_FIFO min/max priority	: 1/99&lt;br /&gt;
SCHED_RR min/max priority	: 1/99&lt;br /&gt;
SCHED_BATCH min/max priority	: 0/0&lt;br /&gt;
SCHED_IDLE min/max priority	: 0/0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
またchrtはプロセスのスケジューリング・ポリシーを変更することが出来ます。詳しくはマニュアル [https://man7.org/linux/man-pages/man1/chrt.1.html chrt] を確認してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムスライスの値はスケジューリングのポリシーによっても変化しますし、スケジューリング・ポリシーによっては動的にも変化します。&lt;br /&gt;
指定されたプロセスの SCHED_RR 間隔を取得するシステムコール[http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html sched_rr_get_interval(2)]を使うと実際の[[プロセスのタイムスライスの値を計測する]]ことが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これらのスケジューリングもカーネルのパラメータを変えることでチューニングができます。ただし、それに関しての説明は本サイトの主旨を越えてしまいますし、当然ながらカーネル内のパラメータを変更するわけですから、不適切な値の場合、システムに大きな損傷を与える可能性があります。ここでは[https://doc.opensuse.org/documentation/leap/archive/42.1/tuning/html/book.sle.tuning/cha.tuning.taskscheduler.html openSUSEのタスクスケジュラーのチューニング]のページを紹介するに留めます。&lt;br /&gt;
&lt;br /&gt;
==== CFS ====&lt;br /&gt;
Linux 2.6.23からCFS(Completely Fair Scheduler)&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Inside the Linux 2.6 Completely Fair Scheduler&lt;br /&gt;
https://developer.ibm.com/tutorials/l-completely-fair-scheduler/&lt;br /&gt;
(リンク切れ)&lt;br /&gt;
Linux カーネル 2.6 Completely Fair Scheduler の内側&lt;br /&gt;
http://www.ibm.com/developerworks/jp/linux/library/l-completely-fair-scheduler/&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は、O(1) スケジューラがヒューリスティック（発見的）にスケジューリングしていたのに対し、CFS のスケジューリングは（数学的な意味で）数値を計算してスケジューリングを決めます。&lt;br /&gt;
ヒューリスティックな方法では、ある種の特定の条件に嵌まってしまいスケジューリングが公平に処理できなくなったり、あるいは偶然に有利な条件になったり不利な条件になったりとする可能性があります。&lt;br /&gt;
それに比べCFSは公平にスケジューリングされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでの Linux のスケジューラは、タスクを管理するキューをもち、その中で処理をしていました。CFSでは平衡2分探索木の一種である&lt;br /&gt;
赤黒木&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
赤黒木がどう生成され管理されるかビジュアルで示してくれるサイトです。挿入(insert)、削除(delete)、検索(find)の操作をすると、どうRed/Black Treeが作られるか/操作されるかがビジュアルでわかります。&lt;br /&gt;
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
というデータ構造を使いタスクを管理します。タスクは仮想実行時間という値を持ち、タスクが実行されるとこの値は増えます。タスク管理のツリーに戻される時、この仮想実行時間の値によってツリー中の適切な位置に置かれます。このツリーの中で最も値の小さいものが次に実行されるべきタスクとなります。こうすることによってCFSは[[計算量]]はO(log n)で、適切なタスクを選ぶという操作が可能になっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今後もある意味オペレーティングシステムの心臓部ともいえるスケジューラが色々な要件を満たすため、&lt;br /&gt;
あるいはさらなる効率化のために変更される可能性は十分にあります。&lt;br /&gt;
これからも、あちらこちらの腕利きのカーネルハッカーがどんどん新しい提案をしてくることでしょう。&lt;br /&gt;
&lt;br /&gt;
=== プライオリティ ===&lt;br /&gt;
     &lt;br /&gt;
UNIX系のオペレーティングシステムではプロセスの持つ動的に変化するプライオリティ値によって、CPUの割当てが変化します。プライオリティ値が小さいものが実行優先順位が高く、大きいものが実行優先順位が低くなります。&lt;br /&gt;
&lt;br /&gt;
プロセス待機キューの並べ変え、プロセスのタイムスライスの値を設定する時に、プライオリティが高い程、よりCPUが割り当てられるような計算がされます。&lt;br /&gt;
&lt;br /&gt;
もう一度、コマンドtopの出力例を見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND&lt;br /&gt;
 6981 hironobu  20   0  6552 6552   140 R    33.4  1.0   0:17 pi&lt;br /&gt;
 6980 hironobu  17   0  6552 6552   140 R    32.8  1.0   0:17 pi&lt;br /&gt;
 6979 hironobu  14   0  6504 6504   140 R    32.6  1.0   0:18 pi&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RRIと書いてあるのがプライオリティ値です。NIと書いてあるのがnice値です。通常で使う範囲では、プロセスがCPUを専有すればするほどプライオリティ値が大きくなっていきます。カーネルの中では0から139の範囲で変化しています。優先順位が0が最低で139が最高です。ユーザ側に表示にされるのは20から-19 で、優先順はプラス側低く、マイナス側が高くなっています。&lt;br /&gt;
&lt;br /&gt;
コマンド実行開始時にコマンドniceを使い底上げ値(優先順位を下げるのでハンディキャップ値といった方がいいかも知れませんが)を与えることができます。一般ユーザは優先順位を下げることしか出来ません。root権限では優先順位を上げることもできます。reniceは既に動いているプロセスのnice値を変更するものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % nice -19 ./setiathome &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足: コマンドniceやreniceで与えるナイス値と、表示されるナイス値、カーネル内部で使うプライオリティ値、表示されるプライオリティ値のプラス／マイナスは間違え安いので注意しましょう。上の例では-19の値を与えているが、topなどのNIの欄の値は19となります。&lt;br /&gt;
&lt;br /&gt;
=== スレッド ===&lt;br /&gt;
&lt;br /&gt;
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。&lt;br /&gt;
ウインドウシステムを考えてみましょう。マウスのようなポインティングデバイスから入力を受け、さらにその位置を計算しポインタのアイコンを変化させつつ、さらに画面書き換えを行うようなプログラムでは効率良く動くプログラムができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次はfork(2)と違い親プロセスの内容をコピーすることなく新しいプロセスを動かすことができるので速くプロセスが生成できることです。&lt;br /&gt;
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。&lt;br /&gt;
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。&lt;br /&gt;
&lt;br /&gt;
* fork版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/wait.h&amp;gt;&lt;br /&gt;
int main(void) {&lt;br /&gt;
  int i,stat;&lt;br /&gt;
  for(i=0;i&amp;lt;1000;i++) {&lt;br /&gt;
    if ( fork() == 0 ) {&lt;br /&gt;
      fprintf(stderr,&amp;quot;.&amp;quot;);&lt;br /&gt;
      _exit(0);&lt;br /&gt;
    }&lt;br /&gt;
    wait(&amp;amp;stat);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O fork.c -o f&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* thread版&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
void *func() { fprintf(stderr,&amp;quot;.&amp;quot;); }&lt;br /&gt;
int main(void) {&lt;br /&gt;
  pthread_t t;&lt;br /&gt;
  int i;&lt;br /&gt;
  for(i=0 ; i &amp;lt; 1000 ; i++) {&lt;br /&gt;
    pthread_create(&amp;amp;t,NULL,func,NULL);&lt;br /&gt;
    pthread_join ( t, NULL );&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;%d\n&amp;quot;,i);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cc -O thread.c -lpthread -o t&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 出力 &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % time ./t&lt;br /&gt;
 ...........(続く)....1000&lt;br /&gt;
 real	0m0.xxxs&lt;br /&gt;
 user	0m0.xxxs&lt;br /&gt;
 sys	0m0.xxxs&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux上でThreadを使う方法に関しての良い資料を見つけることは難しいですが、IBMのLinux情報には良質の説明が載っていました。&amp;lt;ref&amp;gt;&lt;br /&gt;
 Linuxのスレッド http://www-6.ibm.com/jp/developerworks/linux/001208/j_posix1.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== マルチプロセッサとプロセス ===&lt;br /&gt;
&lt;br /&gt;
[[マルチプロセッサとプロセス]]へ移動しました。&lt;br /&gt;
&lt;br /&gt;
=== 脚注 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%82%B9%E3%83%9A%E3%82%B7%E3%83%A3%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB&amp;diff=1726</id>
		<title>デバイススペシャルファイル</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%82%B9%E3%83%9A%E3%82%B7%E3%83%A3%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB&amp;diff=1726"/>
		<updated>2022-08-03T15:22:22Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* I/Oスケジューラ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;第七章&lt;br /&gt;
== デバイススペシャルファイル ==&lt;br /&gt;
&lt;br /&gt;
=== I/O の抽象化 ===&lt;br /&gt;
&lt;br /&gt;
Unix で使われた秀逸なアイデアを3つ上げろといわれたら、多分、多くの人が、階層化ファイルシステム、パイプ、そしてデバイススペシャルファイル（Device Special File : 単にスペシャルファイルとも呼ぶ）&lt;br /&gt;
&amp;lt;ref&amp;gt; wikipediaではデバイス・ファイルの項目に「デバイスファイルまたはスペシャルファイルとは」と書いていますが、UNIXの世界では次のように「デバイススペシャルファイル」という表現をしています。&lt;br /&gt;
[https://www.usenix.org/legacy/event/bsdcon02/full_papers/kamp/kamp_html/ Before we continue, we need to fully understand the &amp;quot;device special file&amp;quot; in UNIX.]&lt;br /&gt;
本稿もそれに従います。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
をあげるでしょう。今回はその中の2つに関係しています。&lt;br /&gt;
デバイスを抽象化するこのアイデアによって、 I/O のデバイスもすべてファイルと同じ統一したインタフェースで扱えるようになりました。&lt;br /&gt;
例えばハードディスクや端末といったものに対して、プロセスから直接ハードウェアにアクセスする必要はありません。&lt;br /&gt;
I/O のスペシャルファイルを経由してアクセスします。&lt;br /&gt;
ディレクトリ /dev 以下に用意されているスペシャルファイルがデバイスへのインタフェースです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
端末もスペシャルファイルとして抽象化されていて、たとえば現在使っている端末は /dev/tty のように見えます。&lt;br /&gt;
ですから、ここに文字をリダイレクトするとスクリーンにその文字が出力されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ echo &#039;hello&#039; &amp;gt; /dev/tty&lt;br /&gt;
 hello&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばLinuxでは /dev/sda は SCSI ハードディスク、あるいは SCSI ハードディスクに見えるものです&amp;lt;ref&amp;gt;たとえば USB メモリは USB マスストレージクラスですが、デバイス用の SCSI エミュレーションによってSCSIデバイスのように見えます。&amp;lt;/ref&amp;gt;。&lt;br /&gt;
Linuxのカーネルが認識した順番に /dev/sda から /dev/sdb 、 /dev/sdc となります。&lt;br /&gt;
/dev/sda はハードディスク全体で、 sda 上にパーティションが設定されていれば /dev/sda1 、 /dev/sda2 ...となります。&lt;br /&gt;
必ずしも /dev/sd? はSCSIハードディスクではなくSCSIのインタフェースが使えて、かつブロックデバイスであればかまいません。&lt;br /&gt;
実際に接続されているのは、コンパクトフラッシュメモリだったり、USB接続の外部HDDだったり、&lt;br /&gt;
あるいはIDE接続のMOがide-scsiデバイスドライバ経由のためSCSI として取り扱われたりと状況でさまざまです。&lt;br /&gt;
IDEハードディスクだと IDE 0 Master に接続されているハードディスクは /dev/hda になります。&lt;br /&gt;
Slave側は hdb、 IDE 1 Master/Slave は hdcと  hdd という具合になります&amp;lt;ref&amp;gt;&lt;br /&gt;
Ubuntuのハードウェアとデバイスの命名規則についての解説ページ [https://www.dell.com/support/kbdoc/ja-jp/000132092/ubuntu-%E3%81%8A%E4%BD%BF%E3%81%84%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%83%89%E3%83%A9%E3%82%A4%E3%83%96%E3%81%8A%E3%82%88%E3%81%B3%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E5%90%91%E3%81%91%E3%81%AE%E6%9D%A1%E4%BB%B6-%E8%AA%AC%E6%98%8E]&lt;br /&gt;
&amp;lt;/ref&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
;補足: 接続した順番にデバイスを決めていくので、USB機器などの接続では挿したタイミングでデバイス名が異なることが発生してしまう場合があります。そこで現在ではUUID(Universally Unique Idenifier )という方式を使ってデバイスをユニークに認識する方法を用意しています。fstab(5)、mount(8)、tune2fs(8)を参照してみてください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/dev/cua0 や /dev/ttyS0 はシリアルポートのスペシャルファイルです。&lt;br /&gt;
cua?はたとえばモデムやFAXモデムを接続しておいて、自分から呼び出して接続を行う(Call-Out)する時に使います。&lt;br /&gt;
ttyS?は相手から呼び出される時に使います。&lt;br /&gt;
/dev/ttyUSB0 はUSB接続をしたシリアル通信のためのスペシャルファイルです。&lt;br /&gt;
&lt;br /&gt;
=== レイヤ図 ===&lt;br /&gt;
&lt;br /&gt;
プログラムは、スペシャルファイルやシステムコールからカーネルを経由し、最後はカーネル内にあるデバイスドライバを経由してハードウェアにアクセスします。下に簡単なレイヤー図を載せます。&lt;br /&gt;
&lt;br /&gt;
[[File:Device-Driver-Layer.png|thumb|right|400px|Device Driver Layer]]&lt;br /&gt;
&lt;br /&gt;
=== ioctl === &lt;br /&gt;
&lt;br /&gt;
ioctl(2)はスペシャルファイルをコントロールしているデバイスドライバに対して命令を送るためのシステムコールです。これでデバイスをコントロールすることになります。（執筆中）&lt;br /&gt;
&lt;br /&gt;
==  デバイス  ==&lt;br /&gt;
=== キャラクタデバイス ===&lt;br /&gt;
&lt;br /&gt;
キャラクタデバイスは、時系列でデータが発生する端末、オーディオ、モデムあるいはテープ装置といったシーケンシャルにバイト単位でアクセスするような入出力を行うデバイスドライバです。&lt;br /&gt;
データはキャッシュしません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l  /dev/{random,tty,st0,midi0}&lt;br /&gt;
 crw-rw----    1 root     audio     35,   0 Mar 15  2002 /dev/midi0&lt;br /&gt;
 crw-rw-rw-    1 root     root       1,   8 Dec  3  2002 /dev/random&lt;br /&gt;
 crw-rw----    1 root     tape       9,   0 Mar 15  2002 /dev/st0&lt;br /&gt;
 crw-rw-rw-    1 root     tty        5,   0 Nov 18 11:35 /dev/tty&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 先頭のcがキャラクタデバイスを意味する&lt;br /&gt;
&lt;br /&gt;
=== ブロックデバイス ===&lt;br /&gt;
&lt;br /&gt;
ブロックデバイスは、ハードディスクのようなランダムアクセスができ、かつ入出力がブロック単位でアクセスを行うことができるハードウェアへのデバイスドライバです。&lt;br /&gt;
データをキャッシュするので効率良く入出力ができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l /dev/hd?&lt;br /&gt;
 brw-rw----    1 root     disk       3,   0 Mar 15  2002 /dev/hda&lt;br /&gt;
 brw-rw----    1 root     disk       3,  64 Mar 15  2002 /dev/hdb&lt;br /&gt;
 ....&lt;br /&gt;
 brw-rw----    1 root     disk      34,   0 Mar 15  2002 /dev/hdg&lt;br /&gt;
 brw-rw----    1 root     disk      34,  64 Mar 15  2002 /dev/hdh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 先頭のbがブロックデバイスを意味する&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
効率が良いと書きましたが、正確には「効率良く入出力するための工夫をしている (だから効率が良い)」といった方がいいでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1つのブロックのことをセクタと呼び、普通はサイズは512バイトです。CD-ROM のようなデバイスでは最近は2KBですが、いずれにしてもセクターは2のN乗倍(512は2 の9乗、2Kは2の11乗)の値を取ります。&lt;br /&gt;
最大値は記憶管理のページのサイズ以下です。&lt;br /&gt;
32ビットアーキテクチャーなら4KB、64ビットアーキテクチャーであれば8KBです&amp;lt;ref&amp;gt;これは典型的な例で、ページサイズはハードウェアのアーキテクチャーに依存します。&amp;lt;/ref&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ハードディスクなどのデバイスからブロックの内容が読み込まれたとき（あるいは書き込まれる途中）、&lt;br /&gt;
データはメモリ中のバッファの中に保管されています。1つのバッファは1つのブロックに対応しています。&lt;br /&gt;
普通はページサイズが4KBでブロックサイズが512 バイトですから、一つのページは複数のバッファから出来ています。&lt;br /&gt;
ブロックデバイスから幾つかのブロックでデータを読み込んで来た時（あるいは書き込もうとした時）、&lt;br /&gt;
メモリ中にバッファのチェーンが作られます。&lt;br /&gt;
このように、ブロックデバイスを読み書きする時には、ハードディスクのようなデバイスを直接読み書きするのではなく、&lt;br /&gt;
まずこのバッファに対して読み書きが行われます。&lt;br /&gt;
&lt;br /&gt;
=== 擬似デバイス ===&lt;br /&gt;
擬似デバイス  (Pseudo-devices) とはデバイスファイルのように見せかけているが、その先には具体的なハードウェアが結びつけられていないデバイスファイルです。&lt;br /&gt;
たとえば /dev/null は、その先が何もないデバイスファイルです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cat foo &amp;gt; /dev/null&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイル foo を読み込んで、デバイスファイル /dev/null に送り込みますが、送り先は何もないので /dev/null に吸い込まれるだけになります。&lt;br /&gt;
/dev/null を入力にした場合、何も送られないことになります。以下にいくつかのデバイスファイル例をあげます。&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
* /dev/null 入力・出力とも何もしない&lt;br /&gt;
* /dev/random , /dev/urandom 乱数を返す&lt;br /&gt;
* /dev/zero ゼロを返す&lt;br /&gt;
&lt;br /&gt;
== I/Oスケジューラ ==&lt;br /&gt;
&lt;br /&gt;
さてまず、バッファに読み書きされることはわかりました。しかしハードディスク、あるいはそれに相当する具体的なブロックデバイスに書き込む、あるいは読み込む必要があります。&lt;br /&gt;
ハードディスクを例に取ると、円盤の磁性体が回っていて、そこに読み書きするヘッドが移動して、そして始めて読み書きが始まります。そのヘッドの移動のことをシークといいますが、ハードディスクのシーク時間は数ミリ秒程度かかります。数ミリ秒というと、とても短い時間のように思えますが、CPUの処理時間から比べれば長い長い時間です。&lt;br /&gt;
&lt;br /&gt;
そこで有効な入出力をするためにスケジューラを用意します。スケジューラの役目は、全体のスループットの改善です。ですから、ある1つのプロセスだけを着目してみると、もしかすると、処理が遅くなっているという可能性もあります。&lt;br /&gt;
この当たりは単純に一つのI/Oスケジューリングのアルゴリズムが万能とはなかなかいかないので、Linux 2.6.0以降では&lt;br /&gt;
Deadline I/O Scheduler、&lt;br /&gt;
&amp;lt;del&amp;gt;Anticipatory I/O Scheduler&amp;lt;/del&amp;gt;&amp;lt;ref&amp;gt;最新ディストリビューションの使っているLinuxカーネルの多くでは既に用意していません。&amp;lt;/ref&amp;gt;、&lt;br /&gt;
Complete Fairness Queueing I/O Scheduler&lt;br /&gt;
&amp;lt;ref&amp;gt; Inside the Linux 2.6 Completely Fair Scheduler https://www.ibm.com/developerworks/library/l-completely-fair-scheduler/index.html&amp;lt;/ref&amp;gt;、&lt;br /&gt;
Noop I/O Scheduler といった複数&lt;br /&gt;
のスケジュールが用意されています。&lt;br /&gt;
またLinux 5.0以降ではI/Oスケジューラがマルチキュー I/O スケジューラに変更され、mq-deadline、bfq (Budget Fair Queueing)、kyber、none &amp;lt;ref&amp;gt;&lt;br /&gt;
https://www.kernel.org/doc/html/latest/block/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
が用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Noop I/O Scheduler (none) はスケジュールをしないスケジューラです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう :  ブロックデバイスが/dev/sdaの場合、I/Oスケジューラの設定は /sys/block/sda/queue/scheduler でされているので、実際に自分の使っている環境ではどうなっているか見てみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : IBMサイトにあるLinuxのディスクI/Oに関する考察 ([http://public.dhe.ibm.com/software/dw/linux390/perf/Linux_disk_IO_considerations.pdf Linux disk I/O considerations ]) や openSUSE サイトにあるI/Oパフォーマンスのチューニング ( [https://doc.opensuse.org/documentation/leap/tuning/html/book-tuning/cha-tuning-io.html#cha-tuning-io-switch 12 Tuning I/O performance] )が参考になります。&lt;br /&gt;
&lt;br /&gt;
== ネットワークデバイス == &lt;br /&gt;
&lt;br /&gt;
1981年当時4.1BSDを改造しTCP/IPのスタックを搭載したのがUNIXのTCP/IPの始まりです&lt;br /&gt;
&amp;lt;ref&amp;gt;私の個人的経験でいわせてもらうと4.2BSDリリース時に入っていたTCP/IPはどう贔屓目に見ても、安定して利用するというには程遠く、プログラム中で引数をちょっと間違えるとシステム全体がいとも簡単にダウンしました。安定して使えたという実感は4.3BSDになってからです。&amp;lt;/ref&amp;gt;&lt;br /&gt;
。&lt;br /&gt;
当時のLANも多くの場合イーサーネット(Ethernet)で構築されていました。&lt;br /&gt;
NIC (Network Interface Card) とか、あるいは LANポート と呼ぶネットワークインタフェースのためのデバイスがあり、&lt;br /&gt;
そのデバイスファイルとして /dev/eth0 が作成されました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: eth0は最初に認識しているイーサネットのネットワークインタフェースのデバイスで、複数のネットワークポートやNICが存在していた場合、 eth1、 eth2... となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
むかしのLinuxもイーサーネットのデバイスは、もちろんUnix流に /dev/ の下にあるデバイススペシャルファイルで、&lt;br /&gt;
デバイスは /dev/eth0 と見えていました。&lt;br /&gt;
ところが今日のLinuxはネットワークデバイスに対してはスペシャルファイルとして用意していません。&lt;br /&gt;
イーサーネットデバイスのはずである/dev/eth?というのはLinux 2.2以降なくなりました。&lt;br /&gt;
理由は単純に1つのイーサーネットのデバイスが、1つのIPアドレスを持つというわけではなくなったからです。&lt;br /&gt;
現在はハードウェアに1つのイーサーネットのポートしかなくても、&lt;br /&gt;
オペレーティングシステムとして、その1つのポートに複数のIPアドレスを割り当てることができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ネットワークインタフェースの設定にはifconfigを使いますが、通常はシステムの設定ファイルに指定のフォーマットで登録しておけば、システムのブート時に設定スクリプトが動き、自動的に割り当ててくれます。Debian系のディストリビューションだと /etc/network/interfaces に、RedHat 系だと /etc/sysconfig/network-scripts/ifcfg-eth0 に記述します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 多くのディストリビューションがifconfigコマンドから [https://wiki.linuxfoundation.org/networking/iproute2 iproute2ユーティリティ] に含まれる ipコマンドに移行しています。頃合いをみて本説明もipコマンドでの説明に切り替える予定です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ネットワークインタフェースの設定状況を見るのには次のようにします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ /sbin/ifconfig&lt;br /&gt;
 eth0     Link encap:Ethernet  HWaddr 00:C0:26:28:12:C5  &lt;br /&gt;
          inet addr:192.168.100.100  Bcast:192.168.100.255  Mask:255.255.255.0&lt;br /&gt;
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1&lt;br /&gt;
 ....&lt;br /&gt;
 lo       Link encap:Local Loopback  &lt;br /&gt;
          inet addr:127.0.0.1  Mask:255.0.0.0&lt;br /&gt;
 ....&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足:  loはループバックのための仮想デバイスです。127.0.0.1は特別なIPアドレスで、これは自分自身を指します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ifconfigを使う以外にも/proc/net/dev/を見ることで現在のネットワークインタフェースのデバイスの状況を確認することができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cat /proc/net/dev&lt;br /&gt;
 Inter-|   Receive  ....&lt;br /&gt;
 face  |bytes    packets errs drop fifo frame ...&lt;br /&gt;
    lo:  321508    2757    0    0    0     0   ...&lt;br /&gt;
 wlan0:       0       0    0    0    0     0    ...&lt;br /&gt;
  eth0: 1087299   17929    0    0    0     0   ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== udev hald ==&lt;br /&gt;
&lt;br /&gt;
ホットプラグを実現するために動的に作られるデバイス（TBD）&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/2d.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%82%B9%E3%83%9A%E3%82%B7%E3%83%A3%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB&amp;diff=1725</id>
		<title>デバイススペシャルファイル</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%82%B9%E3%83%9A%E3%82%B7%E3%83%A3%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB&amp;diff=1725"/>
		<updated>2022-08-03T05:37:54Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* I/O の抽象化 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;第七章&lt;br /&gt;
== デバイススペシャルファイル ==&lt;br /&gt;
&lt;br /&gt;
=== I/O の抽象化 ===&lt;br /&gt;
&lt;br /&gt;
Unix で使われた秀逸なアイデアを3つ上げろといわれたら、多分、多くの人が、階層化ファイルシステム、パイプ、そしてデバイススペシャルファイル（Device Special File : 単にスペシャルファイルとも呼ぶ）&lt;br /&gt;
&amp;lt;ref&amp;gt; wikipediaではデバイス・ファイルの項目に「デバイスファイルまたはスペシャルファイルとは」と書いていますが、UNIXの世界では次のように「デバイススペシャルファイル」という表現をしています。&lt;br /&gt;
[https://www.usenix.org/legacy/event/bsdcon02/full_papers/kamp/kamp_html/ Before we continue, we need to fully understand the &amp;quot;device special file&amp;quot; in UNIX.]&lt;br /&gt;
本稿もそれに従います。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
をあげるでしょう。今回はその中の2つに関係しています。&lt;br /&gt;
デバイスを抽象化するこのアイデアによって、 I/O のデバイスもすべてファイルと同じ統一したインタフェースで扱えるようになりました。&lt;br /&gt;
例えばハードディスクや端末といったものに対して、プロセスから直接ハードウェアにアクセスする必要はありません。&lt;br /&gt;
I/O のスペシャルファイルを経由してアクセスします。&lt;br /&gt;
ディレクトリ /dev 以下に用意されているスペシャルファイルがデバイスへのインタフェースです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
端末もスペシャルファイルとして抽象化されていて、たとえば現在使っている端末は /dev/tty のように見えます。&lt;br /&gt;
ですから、ここに文字をリダイレクトするとスクリーンにその文字が出力されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ echo &#039;hello&#039; &amp;gt; /dev/tty&lt;br /&gt;
 hello&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばLinuxでは /dev/sda は SCSI ハードディスク、あるいは SCSI ハードディスクに見えるものです&amp;lt;ref&amp;gt;たとえば USB メモリは USB マスストレージクラスですが、デバイス用の SCSI エミュレーションによってSCSIデバイスのように見えます。&amp;lt;/ref&amp;gt;。&lt;br /&gt;
Linuxのカーネルが認識した順番に /dev/sda から /dev/sdb 、 /dev/sdc となります。&lt;br /&gt;
/dev/sda はハードディスク全体で、 sda 上にパーティションが設定されていれば /dev/sda1 、 /dev/sda2 ...となります。&lt;br /&gt;
必ずしも /dev/sd? はSCSIハードディスクではなくSCSIのインタフェースが使えて、かつブロックデバイスであればかまいません。&lt;br /&gt;
実際に接続されているのは、コンパクトフラッシュメモリだったり、USB接続の外部HDDだったり、&lt;br /&gt;
あるいはIDE接続のMOがide-scsiデバイスドライバ経由のためSCSI として取り扱われたりと状況でさまざまです。&lt;br /&gt;
IDEハードディスクだと IDE 0 Master に接続されているハードディスクは /dev/hda になります。&lt;br /&gt;
Slave側は hdb、 IDE 1 Master/Slave は hdcと  hdd という具合になります&amp;lt;ref&amp;gt;&lt;br /&gt;
Ubuntuのハードウェアとデバイスの命名規則についての解説ページ [https://www.dell.com/support/kbdoc/ja-jp/000132092/ubuntu-%E3%81%8A%E4%BD%BF%E3%81%84%E3%81%AE%E3%83%8F%E3%83%BC%E3%83%89%E3%83%89%E3%83%A9%E3%82%A4%E3%83%96%E3%81%8A%E3%82%88%E3%81%B3%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E5%90%91%E3%81%91%E3%81%AE%E6%9D%A1%E4%BB%B6-%E8%AA%AC%E6%98%8E]&lt;br /&gt;
&amp;lt;/ref&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
;補足: 接続した順番にデバイスを決めていくので、USB機器などの接続では挿したタイミングでデバイス名が異なることが発生してしまう場合があります。そこで現在ではUUID(Universally Unique Idenifier )という方式を使ってデバイスをユニークに認識する方法を用意しています。fstab(5)、mount(8)、tune2fs(8)を参照してみてください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/dev/cua0 や /dev/ttyS0 はシリアルポートのスペシャルファイルです。&lt;br /&gt;
cua?はたとえばモデムやFAXモデムを接続しておいて、自分から呼び出して接続を行う(Call-Out)する時に使います。&lt;br /&gt;
ttyS?は相手から呼び出される時に使います。&lt;br /&gt;
/dev/ttyUSB0 はUSB接続をしたシリアル通信のためのスペシャルファイルです。&lt;br /&gt;
&lt;br /&gt;
=== レイヤ図 ===&lt;br /&gt;
&lt;br /&gt;
プログラムは、スペシャルファイルやシステムコールからカーネルを経由し、最後はカーネル内にあるデバイスドライバを経由してハードウェアにアクセスします。下に簡単なレイヤー図を載せます。&lt;br /&gt;
&lt;br /&gt;
[[File:Device-Driver-Layer.png|thumb|right|400px|Device Driver Layer]]&lt;br /&gt;
&lt;br /&gt;
=== ioctl === &lt;br /&gt;
&lt;br /&gt;
ioctl(2)はスペシャルファイルをコントロールしているデバイスドライバに対して命令を送るためのシステムコールです。これでデバイスをコントロールすることになります。（執筆中）&lt;br /&gt;
&lt;br /&gt;
==  デバイス  ==&lt;br /&gt;
=== キャラクタデバイス ===&lt;br /&gt;
&lt;br /&gt;
キャラクタデバイスは、時系列でデータが発生する端末、オーディオ、モデムあるいはテープ装置といったシーケンシャルにバイト単位でアクセスするような入出力を行うデバイスドライバです。&lt;br /&gt;
データはキャッシュしません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l  /dev/{random,tty,st0,midi0}&lt;br /&gt;
 crw-rw----    1 root     audio     35,   0 Mar 15  2002 /dev/midi0&lt;br /&gt;
 crw-rw-rw-    1 root     root       1,   8 Dec  3  2002 /dev/random&lt;br /&gt;
 crw-rw----    1 root     tape       9,   0 Mar 15  2002 /dev/st0&lt;br /&gt;
 crw-rw-rw-    1 root     tty        5,   0 Nov 18 11:35 /dev/tty&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 先頭のcがキャラクタデバイスを意味する&lt;br /&gt;
&lt;br /&gt;
=== ブロックデバイス ===&lt;br /&gt;
&lt;br /&gt;
ブロックデバイスは、ハードディスクのようなランダムアクセスができ、かつ入出力がブロック単位でアクセスを行うことができるハードウェアへのデバイスドライバです。&lt;br /&gt;
データをキャッシュするので効率良く入出力ができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l /dev/hd?&lt;br /&gt;
 brw-rw----    1 root     disk       3,   0 Mar 15  2002 /dev/hda&lt;br /&gt;
 brw-rw----    1 root     disk       3,  64 Mar 15  2002 /dev/hdb&lt;br /&gt;
 ....&lt;br /&gt;
 brw-rw----    1 root     disk      34,   0 Mar 15  2002 /dev/hdg&lt;br /&gt;
 brw-rw----    1 root     disk      34,  64 Mar 15  2002 /dev/hdh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 先頭のbがブロックデバイスを意味する&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
効率が良いと書きましたが、正確には「効率良く入出力するための工夫をしている (だから効率が良い)」といった方がいいでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1つのブロックのことをセクタと呼び、普通はサイズは512バイトです。CD-ROM のようなデバイスでは最近は2KBですが、いずれにしてもセクターは2のN乗倍(512は2 の9乗、2Kは2の11乗)の値を取ります。&lt;br /&gt;
最大値は記憶管理のページのサイズ以下です。&lt;br /&gt;
32ビットアーキテクチャーなら4KB、64ビットアーキテクチャーであれば8KBです&amp;lt;ref&amp;gt;これは典型的な例で、ページサイズはハードウェアのアーキテクチャーに依存します。&amp;lt;/ref&amp;gt;。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ハードディスクなどのデバイスからブロックの内容が読み込まれたとき（あるいは書き込まれる途中）、&lt;br /&gt;
データはメモリ中のバッファの中に保管されています。1つのバッファは1つのブロックに対応しています。&lt;br /&gt;
普通はページサイズが4KBでブロックサイズが512 バイトですから、一つのページは複数のバッファから出来ています。&lt;br /&gt;
ブロックデバイスから幾つかのブロックでデータを読み込んで来た時（あるいは書き込もうとした時）、&lt;br /&gt;
メモリ中にバッファのチェーンが作られます。&lt;br /&gt;
このように、ブロックデバイスを読み書きする時には、ハードディスクのようなデバイスを直接読み書きするのではなく、&lt;br /&gt;
まずこのバッファに対して読み書きが行われます。&lt;br /&gt;
&lt;br /&gt;
=== 擬似デバイス ===&lt;br /&gt;
擬似デバイス  (Pseudo-devices) とはデバイスファイルのように見せかけているが、その先には具体的なハードウェアが結びつけられていないデバイスファイルです。&lt;br /&gt;
たとえば /dev/null は、その先が何もないデバイスファイルです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cat foo &amp;gt; /dev/null&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイル foo を読み込んで、デバイスファイル /dev/null に送り込みますが、送り先は何もないので /dev/null に吸い込まれるだけになります。&lt;br /&gt;
/dev/null を入力にした場合、何も送られないことになります。以下にいくつかのデバイスファイル例をあげます。&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
* /dev/null 入力・出力とも何もしない&lt;br /&gt;
* /dev/random , /dev/urandom 乱数を返す&lt;br /&gt;
* /dev/zero ゼロを返す&lt;br /&gt;
&lt;br /&gt;
== I/Oスケジューラ ==&lt;br /&gt;
&lt;br /&gt;
さてまず、バッファに読み書きされることはわかりました。しかしハードディスク、あるいはそれに相当する具体的なブロックデバイスに書き込む、あるいは読み込む必要があります。&lt;br /&gt;
ハードディスクを例に取ると、円盤の磁性体が回っていて、そこに読み書きするヘッドが移動して、そして始めて読み書きが始まります。そのヘッドの移動のことをシークといいますが、ハードディスクのシーク時間は数ミリ秒程度かかります。数ミリ秒というと、とても短い時間のように思えますが、CPUの処理時間から比べれば長い長い時間です。&lt;br /&gt;
&lt;br /&gt;
そこで有効な入出力をするためにスケジューラを用意します。スケジューラの役目は、全体のスループットの改善です。ですから、ある1つのプロセスだけを着目してみると、もしかすると、処理が遅くなっているという可能性もあります。&lt;br /&gt;
この当たりは単純に一つのI/Oスケジューリングのアルゴリズムが万能とはなかなかいかないので、Linux 2.6.0以降では&lt;br /&gt;
Deadline I/O Scheduler、&lt;br /&gt;
&amp;lt;del&amp;gt;Anticipatory I/O Scheduler&amp;lt;/del&amp;gt;&amp;lt;ref&amp;gt;最新ディストリビューションの使っているLinuxカーネルの多くでは既に用意していません。&amp;lt;/ref&amp;gt;、&lt;br /&gt;
Complete Fairness Queueing I/O Scheduler&lt;br /&gt;
&amp;lt;ref&amp;gt; Inside the Linux 2.6 Completely Fair Scheduler https://www.ibm.com/developerworks/library/l-completely-fair-scheduler/index.html&amp;lt;/ref&amp;gt;、&lt;br /&gt;
Noop I/O Scheduler といった複数&lt;br /&gt;
のスケジュールが用意されています。&lt;br /&gt;
またLinux 5.0以降ではI/Oスケジューラがマルチキュー I/O スケジューラに変更され、mq-deadline、bfq (Budget Fair Queuing)、kyber、none &amp;lt;ref&amp;gt;&lt;br /&gt;
https://www.kernel.org/doc/html/latest/block/index.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
が用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Noop I/O Scheduler (none) はスケジュールをしないスケジューラです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう :  ブロックデバイスが/dev/sdaの場合、I/Oスケジューラの設定は /sys/block/sda/queue/scheduler でされているので、実際に自分の使っている環境ではどうなっているか見てみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : IBMサイトにあるLinuxのディスクI/Oに関する考察 ([http://public.dhe.ibm.com/software/dw/linux390/perf/Linux_disk_IO_considerations.pdf Linux disk I/O considerations ]) や openSUSE サイトにあるI/Oパフォーマンスのチューニング ( [https://doc.opensuse.org/documentation/leap/tuning/html/book-tuning/cha-tuning-io.html#cha-tuning-io-switch 12 Tuning I/O performance] )が参考になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ネットワークデバイス == &lt;br /&gt;
&lt;br /&gt;
1981年当時4.1BSDを改造しTCP/IPのスタックを搭載したのがUNIXのTCP/IPの始まりです&lt;br /&gt;
&amp;lt;ref&amp;gt;私の個人的経験でいわせてもらうと4.2BSDリリース時に入っていたTCP/IPはどう贔屓目に見ても、安定して利用するというには程遠く、プログラム中で引数をちょっと間違えるとシステム全体がいとも簡単にダウンしました。安定して使えたという実感は4.3BSDになってからです。&amp;lt;/ref&amp;gt;&lt;br /&gt;
。&lt;br /&gt;
当時のLANも多くの場合イーサーネット(Ethernet)で構築されていました。&lt;br /&gt;
NIC (Network Interface Card) とか、あるいは LANポート と呼ぶネットワークインタフェースのためのデバイスがあり、&lt;br /&gt;
そのデバイスファイルとして /dev/eth0 が作成されました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: eth0は最初に認識しているイーサネットのネットワークインタフェースのデバイスで、複数のネットワークポートやNICが存在していた場合、 eth1、 eth2... となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
むかしのLinuxもイーサーネットのデバイスは、もちろんUnix流に /dev/ の下にあるデバイススペシャルファイルで、&lt;br /&gt;
デバイスは /dev/eth0 と見えていました。&lt;br /&gt;
ところが今日のLinuxはネットワークデバイスに対してはスペシャルファイルとして用意していません。&lt;br /&gt;
イーサーネットデバイスのはずである/dev/eth?というのはLinux 2.2以降なくなりました。&lt;br /&gt;
理由は単純に1つのイーサーネットのデバイスが、1つのIPアドレスを持つというわけではなくなったからです。&lt;br /&gt;
現在はハードウェアに1つのイーサーネットのポートしかなくても、&lt;br /&gt;
オペレーティングシステムとして、その1つのポートに複数のIPアドレスを割り当てることができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ネットワークインタフェースの設定にはifconfigを使いますが、通常はシステムの設定ファイルに指定のフォーマットで登録しておけば、システムのブート時に設定スクリプトが動き、自動的に割り当ててくれます。Debian系のディストリビューションだと /etc/network/interfaces に、RedHat 系だと /etc/sysconfig/network-scripts/ifcfg-eth0 に記述します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 多くのディストリビューションがifconfigコマンドから [https://wiki.linuxfoundation.org/networking/iproute2 iproute2ユーティリティ] に含まれる ipコマンドに移行しています。頃合いをみて本説明もipコマンドでの説明に切り替える予定です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ネットワークインタフェースの設定状況を見るのには次のようにします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ /sbin/ifconfig&lt;br /&gt;
 eth0     Link encap:Ethernet  HWaddr 00:C0:26:28:12:C5  &lt;br /&gt;
          inet addr:192.168.100.100  Bcast:192.168.100.255  Mask:255.255.255.0&lt;br /&gt;
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1&lt;br /&gt;
 ....&lt;br /&gt;
 lo       Link encap:Local Loopback  &lt;br /&gt;
          inet addr:127.0.0.1  Mask:255.0.0.0&lt;br /&gt;
 ....&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;補足:  loはループバックのための仮想デバイスです。127.0.0.1は特別なIPアドレスで、これは自分自身を指します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ifconfigを使う以外にも/proc/net/dev/を見ることで現在のネットワークインタフェースのデバイスの状況を確認することができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cat /proc/net/dev&lt;br /&gt;
 Inter-|   Receive  ....&lt;br /&gt;
 face  |bytes    packets errs drop fifo frame ...&lt;br /&gt;
    lo:  321508    2757    0    0    0     0   ...&lt;br /&gt;
 wlan0:       0       0    0    0    0     0    ...&lt;br /&gt;
  eth0: 1087299   17929    0    0    0     0   ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== udev hald ==&lt;br /&gt;
&lt;br /&gt;
ホットプラグを実現するために動的に作られるデバイス（TBD）&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/2d.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1724</id>
		<title>ユーザ権限とアクセス制御</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%83%A6%E3%83%BC%E3%82%B6%E6%A8%A9%E9%99%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E5%BE%A1&amp;diff=1724"/>
		<updated>2022-06-14T05:09:35Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* ユーザと権限 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== ユーザと権限  ==&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステム内部ではユーザの違いをアカウント名ではなく&lt;br /&gt;
ユーザID(UID / User IDentifier)による数値で認識しています。&lt;br /&gt;
またユーザは1つデフォルトのグループID(GID / GroupIDentifier)がつけられています。&lt;br /&gt;
そのユーザIDやグループIDが条件に合致するかどうかでユーザに権限があるかどうかを判断しています。&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
RED HAT ENTERPRISE LINUX Identity Management ガイド&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/6/html/identity_management_guide/index&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: ユーザやグループの追加、更新などオペレーションに関しては[[ユーザやグループの管理]]を参照してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
唯一例外的なのはユーザIDが0、グループIDが0のユーザrootです。&lt;br /&gt;
スーパーユーザーと呼ばれ、&lt;br /&gt;
UNIXにおいてはオールマイティーな権限を持つ特別なユーザです。&lt;br /&gt;
管理者権限として説明される場合が多いのですが、&lt;br /&gt;
管理者として何かするという表現よりも「オペレーティングシステム上で何でもできてしまう権限」&lt;br /&gt;
と説明した方が分かり易いかと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ユーザIDとグループIDによるアクセス制御 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの内部では、ユーザは名前で管理されているのではなくユーザID(UID)で管理されています。&lt;br /&gt;
たとえばファイルにユーザ(所有者)が設定されていますが、その所有者情報とはファイルの情報（ディレクトリ情報のなかにあるメタ情報）に付加されているユーザIDのことです。&lt;br /&gt;
また、プロセスが動作している時には、いずれかのユーザIDとグループIDを持っており、そのユーザIDに付加された権限の範囲内においてプロセスは資源にアクセスできます。&lt;br /&gt;
グループID(GID)は、そのグループにユーザが登録されている場合、そのユーザに与えられるグループ権限です。&lt;br /&gt;
UNIXの基本的な権限は、このユーザIDの違いによるユーザ権限と、グループIDの違いによるグループ権限の2つから成り立っています。&lt;br /&gt;
ファイルやプロセスの資源へのアクセス制御はユーザID・グループID&lt;br /&gt;
&amp;lt;ref&amp;gt;自分のユーザIDやグループIDを確認するにはコマンドidを使う。詳しくは[[ユーザやグループの管理]]を参照のこと。&amp;lt;/ref&amp;gt;&lt;br /&gt;
を使っての許可・不許可によって行われるというのが基本的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずファイルに対するユーザIDとグループIDを見てみましょう。&lt;br /&gt;
ファイルには、ユーザIDとグループIDが設定されています。&lt;br /&gt;
ユーザID＝このファイルの所有者です。&lt;br /&gt;
尚、本章の範囲では、所有者とユーザと同じ意味で使っています。&lt;br /&gt;
ユーザが自分の所有するファイルの属性を変更し、そのファイルのアクセス権限などをコントロールすることができます。&lt;br /&gt;
ただしroot権限だけは例外で、システムのすべてに無制限にアクセスできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ユーザIDが数字ではなくユーザ名として表示されるのは、ユーザIDは/etc/passwdで設定されている対応するアカウント名、&lt;br /&gt;
グループIDは/etc/groupで設定されている対応するグループ名に変換されて表示されるからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 読み込み / 書き込み  / 実行 ===&lt;br /&gt;
&lt;br /&gt;
基本的なファイルへのアクセス権限は、「読み込み」「書き込み」「実行」です。&lt;br /&gt;
ディレクトリの場合は実行の部分の意味が「ディレクトリとしてアクセスできるか」ということとして扱われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*  アクセス権限 : 読み込み / 書き込み / 実行&lt;br /&gt;
*  ユーザ・所有者(User)に対して : 許可 / 不許可&lt;br /&gt;
*  グループ(Group)に対して : 許可 / 不許可&lt;br /&gt;
*  それ以外(Other)対して : 許可 / 不許可&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-r--r--    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
 $  ls -l /var/mail/hironobu&lt;br /&gt;
 -rw-rw----    1 hironobu mail            0 Dec  9 19:39 hironobu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
memo.txtはユーザIDがhironobu、グループIDがhironobuになっており、ユーザ（所有者）は読み書き、同じグループには読み込み、その他の権限でも読み込みができます。&lt;br /&gt;
正確には、ユーザと同じユーザIDを持ったプロセス、設定されたグループと同じグループに属するユーザIDを持つプロセス、それ以外のユーザIDを持つプロセスがアクセス可能であるという表現になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/var/mail/hironobuというファイルのユーザIDはhironobuになっており、グループIDはmailです。mailのグループ権限を持つプロセスから読み書き可能になっています。具体的には、メールサーバなどのプロセスが読み書きできるようになっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
変更はコマンドchmodを使います。chmodのオプションではユーザ（所有者）はu、グループはg、それ以外の利用者はoという表現を使います。&lt;br /&gt;
パーミッションの許可は&amp;quot;+&amp;quot;、パーミッションの不許可は&amp;quot;-&amp;quot;を使います。&lt;br /&gt;
chmodのオプションで&amp;quot;go-rw&amp;quot;はグループとその他ユーザからの読み書きは不許可となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ユーザ（所有者）、グループ、その他ユーザの読み取り許可・不許可、書き込み許可・不許可、実行の許可・不許可は3ビットで表すので、この部分を8進数で表現することもできます。&lt;br /&gt;
その場合&amp;quot;rw-------&amp;quot;はビットの設定がuが110、gが000、oが000となるので、8進数表現をするモードでは600となります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 600 memo.txt&lt;br /&gt;
 $ ls -l memo.txt &lt;br /&gt;
 -rw-------    1 hironobu hironobu       44 Sep 20 19:17 memo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== グループID利用の方法 == &lt;br /&gt;
&lt;br /&gt;
ここにファイルgroup_share.datがあるとします。これをユーザtaroとユーザhanakoが共通に読み書きのアクセスでき、&lt;br /&gt;
他のユーザはアクセスできないようなパーミッションにしたいとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-r--r--  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずgroup_share.datを所有者とグループにはrw、それ以外には読み書き禁止にします。&lt;br /&gt;
chmodを使いますが、2度に分けてオプションを使ってもいいですし、モードを数字で与えてもかまいません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod o-wr group_share.dat &lt;br /&gt;
 $ chmod g+wr group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
あるいは&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod 660 group_share.dat &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
結果は次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ls -l&lt;br /&gt;
 合計 56&lt;br /&gt;
 -rw-rw----  1 taro taro     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次にroot権限でtaroとhanakoの共通に使えるグループtaro-hanakoを作ります。&lt;br /&gt;
そしてtaro とhanakoをグループtaro-hanakoに加えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 # groupadd taro-hanako&lt;br /&gt;
 # gpasswd -a taro   taro-hanako&lt;br /&gt;
 # gpasswd -a hanako taro-hanako&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
taroが新しいグループに加わった時、taroが再度ログインした時からその新しいグループ (この場合taro-hanako)が有効になります。&lt;br /&gt;
再度ログインした状態で、taroはgroup_share.datのグループIDをtaro-hanakoにします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chgrp taro-hanako group_share.dat&lt;br /&gt;
 ...&lt;br /&gt;
 -rw-rw----  1 taro taro-hanako     51200 2005-11-23 18:33 group_share.dat&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これでgroup_share.datはtaro-hanakoのグループに属しているtaroとhanakoが読み書きが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;考えてみよう: apacheはユーザwww-dataの権限で動作しています。cgi-binなどでコマンドを動かしファイルinfo.datに情報を書き込む必要があります。しかし、info.dataの中身に関してはセキュリティ上の問題のためユーザfoo以外には読ませたくありません(www-dataにも許可しません)。さて、この場合、info.datの適切なファイルの所有者、適切なパーミッションはどのようなものでしょうか。&lt;br /&gt;
&lt;br /&gt;
== プロセスのユーザIDとグループID ==&lt;br /&gt;
&lt;br /&gt;
まずログインした時に、そのアカウント名に割り振られたユーザIDとグループIDの権限でログインシェルが動き始めます。&lt;br /&gt;
そのシェルから起動されるプロセスにはデフォルトで親プロセスのユーザIDとグループIDが受け継がれます。&lt;br /&gt;
root権限(注)でsetuid(2)やsetgid(2)を使うとプロセスのユーザIDを変更することができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: setuid(2)やsetgid(2)の利用にはもう少し限定した条件があるので調べてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps aux&lt;br /&gt;
 USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND&lt;br /&gt;
 root         1  0.0  0.0  1272  432 ?        S    Aug23   1:49 init [2]       &lt;br /&gt;
 ...&lt;br /&gt;
 daemon     126  0.0  0.0  1384  296 ?        S    Aug23   0:00 /sbin/portmap&lt;br /&gt;
 canna     2799  0.0  2.7 19152 17568 ?       S    Aug23  13:02 /usr/sbin/cannase&lt;br /&gt;
 root     23439  0.0  0.1  2936  660 ?        S    Nov24   0:17 /usr/sbin/apache&lt;br /&gt;
 www-data 23474  0.0  0.0  2948  632 ?        S    Nov24   0:00 /usr/sbin/apache&lt;br /&gt;
 hironobu 20287  0.0  0.0  2464  224 pts/0    S    Oct16   0:00 bash&lt;br /&gt;
 hironobu  2796  0.0  1.0  8752 6716 ?        R    12:14   0:05 emacs20 -geometry&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 現在の権限管理 === &lt;br /&gt;
&lt;br /&gt;
古典的なUNIXはUIDとGIDだけで説明は済みますが、Linuxも含めBSD 4.3以降では、もっと複雑な設定ができます。&lt;br /&gt;
Linuxでは4つタイプのUIDと4つのGIDのタイプを持っています。&lt;br /&gt;
&lt;br /&gt;
*  ユーザID、グループIDの種類&lt;br /&gt;
* UID / GID : 今まで通りのUID / GID &lt;br /&gt;
* RUID / RGID : 実UID / 実GID --- UIDやGIDと同じ役割 (RはReal)&lt;br /&gt;
* EUID / EGID : 実効UID / 実効GID --- 権限があるかどうかをチェックする時に使う (EはEffective)&lt;br /&gt;
* SUID / SGID : 保存UID / 保存GID --- 有効化・無効化を行うための保存 (SはSaved)&lt;br /&gt;
* FSUID / FSGID : ファイルUID / ファイルGID --- Linux独自のファイルのアクセス権限のチェック&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== setuid  === &lt;br /&gt;
&lt;br /&gt;
これらはプロセスが、どのような権限で動作するかを規定するものです。&lt;br /&gt;
UNIXには実行ファイルの属性に(モードに)setuid bitを設定しておくと、&lt;br /&gt;
その実行ファイルはファイルの所有者の権限で動作します。&lt;br /&gt;
setgid bitは実行ファイルのグループの権限で動作します。&lt;br /&gt;
コマンドfindを使って探してみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +a+s -exec ls -l {} \;&lt;br /&gt;
 -rwsr-xr-x 1 root root 26252 Mar  3  2012 /bin/fusermount&lt;br /&gt;
 -rwsr-xr-x 1 root root 88760 Mar 30  2012 /bin/mount&lt;br /&gt;
 -rwsr-xr-x 1 root root 34740 Nov  8  2011 /bin/ping&lt;br /&gt;
 -rwsr-xr-x 1 root root 39116 Nov  8  2011 /bin/ping6&lt;br /&gt;
 -rwsr-xr-x 1 root root 31116 Sep 13  2012 /bin/su&lt;br /&gt;
 -rwsr-xr-x 1 root root 67720 Mar 30  2012 /bin/umount&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初の表示にある-rwsr-x-rxのsがsetuid bitの意味です。&lt;br /&gt;
つまり、これらのコマンドは所有者がrootであり、かつ、&lt;br /&gt;
このコマンドを動かすとrootの権限で動かすことができるという意味です。&lt;br /&gt;
この実行時は、ruidは利用者、euidがrootとなり、&lt;br /&gt;
root権限のファイルなどに書き込むことができるようになります。&lt;br /&gt;
一般ユーザでも何でもできる権限を手に入れてしまうということで、&lt;br /&gt;
このようなプログラムに誤りがあると大きなセキュリティ上の問題になります。&lt;br /&gt;
&lt;br /&gt;
=== setgid === &lt;br /&gt;
&lt;br /&gt;
setgidは、set group id bitの意味です。そのファイルのグループIDと同じ権限で実行できます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ find /bin  -perm +g+s -exec ls -l {} \;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ruidがrootの時、つまりrootがファイルを実行した時は何でもできるので、euidをプロセス内で制限なく変更できます。&lt;br /&gt;
たとえばapacheは唯一1つrootでのプロセスがあり、&lt;br /&gt;
そこから生成し子プロセスがwww-data（あるいは他の）euidで動作します。&lt;br /&gt;
外部からのアクセスはすべてwww-dataのeuidで動いている子プロセスで動作しているので、&lt;br /&gt;
万が一、外部からの入力によりapache誤った動作をしても、&lt;br /&gt;
その影響範囲を無制限にはしない（root権限ではない）ようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
RUID/RGID、EUID/EGID、SUID/SGIDを上手に変更することによって、どのユーザ権限で、&lt;br /&gt;
あるいはどのグループ権限でプロセスを動かし、適切にファイルや資源にアクセスできるようになることで、&lt;br /&gt;
セキュリティを保つことができるようになります。&lt;br /&gt;
これらの値のセットにはルールがあるので、全部はかけないですが、典型的なものを書き出してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* RUID / EUID / SUIDの設定ルール&lt;br /&gt;
*  RUID の値を  EUID にセットできる&lt;br /&gt;
* EUID の値を  RUID にセットできる&lt;br /&gt;
* 実行時のEUIDがSUIDにコピーされていて、SUIDの値をEUIDにセットできる&lt;br /&gt;
* rootはRUIDもEUIDも自由にセットできる&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように実行時のユーザIDを変えることができ、また一般ユーザでも実行ファイルに権限が附加されていれば、&lt;br /&gt;
root権限でプロセスを動かすこともできるなどかなり複雑な権限のコントロールが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もちろん、Linuxがコントロールが可能であることと、&lt;br /&gt;
アプリケーションがきちんと矛盾なく利用できるように設計できることとはまったく別のことです。&lt;br /&gt;
アプリケーションの設計が正しくなかったり、実装で間違えていると、セキュリティ侵害が発生することはいうまでもありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== なるべくrootでは動かさない運用 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まだセキュリティなどをあまり気にせず、サーバとして動作しているものは何でもかんでもrootで実行していた時期がUNIXにもありました。&lt;br /&gt;
これの利点は、アクセスする先のファイルのパーミッションやroot権限でしかオープンできないポート番号など一々気にしなくてもかまわないという点です。&lt;br /&gt;
しかし、万が一、このサーバプロセスが何かの形で乗っ取られてしまい侵入者が外部から任意のコマンドを動かすことが出来るなら、侵入者にシステムに対して万能の権限を持ってしまうことになります。&lt;br /&gt;
現在では実行権限はなるべく絞る形で運用されています。&lt;br /&gt;
たとえばhttpd(apache)は1つだけrootで稼働しポートのオープンや子プロセスを生成するといった処理をします。&lt;br /&gt;
実際のHTTPリクエストに対する対応は別の権限を与えて実行しています。たとえば下の例だとapache/apacheの権限でプロセスを動作させています。&lt;br /&gt;
万が一、外部から不当なコマンドが動かされる事態になっても、apacheのユーザ権限が及ぶ範囲でしか被害がありません。&lt;br /&gt;
システムの書き換えなど重大なセキュリティ侵害からシステムを守り被害を最小限にできるようなシステムの設計にするのが現在の一般的な考え方です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
% ps -eo user,group,args | grep httpd&lt;br /&gt;
root     root     /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
apache   apache   /usr/sbin/httpd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ディレクトリへの特殊な設定 ==&lt;br /&gt;
=== ディレクトリにsetgidビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ディレクトリのグループにsetgidビットを設定すると、そのディレクトリ以下に作られるファイル及びディレクトリには現ディレクトリのグループが適用されます。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ ls -l&lt;br /&gt;
合計 4&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:35 foo&lt;br /&gt;
$ sudo touch foo/fileA&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrwx--- 2 hironobu hironobu 4096 12月 14 02:36 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
この例は、fooというディレクトリがあり、そのディレクトリ下にコマンド touch を使いrootの持ち物である fileA を作成します。&lt;br /&gt;
この時のfileAの所有者、グループともrootです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ chmod g+s foo&lt;br /&gt;
$ ls -ld foo&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:36 foo&lt;br /&gt;
$ sudo touch foo/fileB&lt;br /&gt;
$ ls -al foo&lt;br /&gt;
合計 8&lt;br /&gt;
drwxrws--- 2 hironobu hironobu 4096 12月 14 02:37 .&lt;br /&gt;
drwxrwx--- 3 hironobu hironobu 4096 12月 14 02:35 ..&lt;br /&gt;
-rw-r----- 1 root     root        0 12月 14 02:36 fileA&lt;br /&gt;
-rw-r----- 1 root     hironobu    0 12月 14 02:37 fileB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ディレクトリ foo に対しsetgid ビットの設定を行います。setgid ビットがセットされるとグループの&amp;quot;x&amp;quot;だった部分が&amp;quot;s&amp;quot;に変化します。&lt;br /&gt;
次にコマンド touch で fileB を作成します。 &lt;br /&gt;
ディレクトリのグループ hironobu がファイルに継承されて fileB の所有者は root グループが hironobu になります。&lt;br /&gt;
&lt;br /&gt;
=== ディレクトリにStickyビットを設定する ===&lt;br /&gt;
&lt;br /&gt;
ユーザ(user)が読み書きできるディレクトリにStickyビットを設定した場合、そのディレクトリにどのユーザでもファイルを作成することができますが、ディレクトリから削除する場合、そのファイルの所有者(owner)しか削除できません。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
$ mkdir temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxr----- 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
$ chmod go+rwxt temp&lt;br /&gt;
$ ls -dl temp&lt;br /&gt;
drwxrwxrwt 2 hironobu hironobu 4096 12月 14 03:12 temp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ACL ==&lt;br /&gt;
&lt;br /&gt;
Access Control Lists（ACL）は元々のUNIXにはないアクセス制御方式で、その仕様に関してはPOSIXで定義されています。Linuxカーネル2.6以降で採用されています。Linuxカーネル2.6以降ではLinuxの主要ファイルシステムで利用可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXでは自分以外のユーザにアクセスを許可する場合は、グループに許可するか、それともすべてのユーザに許可するかの大まかな条件でアクセス制御をしています。一方、ACLではアクセス許可を特定のユーザの単位で、あるいはグループ単位で設定できます。ACLの導入により、これまでのUNIXのアクセス制御よりも現敵的な設定をすることが可能になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次のようなファイルがあるとします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $touch foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw-rw-r-- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コマンドgetfaclを使ってパーミッションを表示すると次のようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt &lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 group::rw-&lt;br /&gt;
 other::r--&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次に自分以外のユーザが読み書きできないようにしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ chmod go-rw foo.txt&lt;br /&gt;
 $ ls -l foo.txt&lt;br /&gt;
 -rw------- 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この状態でwww-dataユーザのみにfoo.txtの読み込みを許諾するとなると、グループを使う方法だとwww-dataとhironobuだけのグループを作り、そのグループを設定し、グループの読み込みを許可する、といったことをしなければなりません。このWebサーバがアクセスしなければならないファイルの所有者がhironobuのユーザしか存在していないのならば、グループで運用するのも問題ありません。しかし、もし、hironobu以外にmasamiというユーザがいたならば、双方別々のグループを作りwww-dataを加えるといった方法が必要になります。もちろんこの方法はユーザが増えるたびにグループも増えます。&lt;br /&gt;
&lt;br /&gt;
そこでACLの登場です。www-dataのアカウントのみを直接指定してアクセスを許すといった個別の対応ができれば、これまでのUNIXのアクセス権限の手法よりもシンプルに扱うことが出来るようになります。&lt;br /&gt;
&lt;br /&gt;
=== ACLの設定 ===&lt;br /&gt;
&lt;br /&gt;
コマンドsetfaclはaclをセットするためのものです。ユーザwww-dataに&amp;quot;r&amp;quot;だけ許可をしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ setfacl -m user:www-data:r foo.txt &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ではコマンドgetfaclを使って、どう変化したか見てみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ getfacl foo.txt&lt;br /&gt;
 # file: foo.txt&lt;br /&gt;
 # owner: hironobu&lt;br /&gt;
 # group: hironobu&lt;br /&gt;
 user::rw-&lt;br /&gt;
 user:www-data:r--&lt;br /&gt;
 group::---&lt;br /&gt;
 mask::r--&lt;br /&gt;
 other::---&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
先ほどの内容から2点変わっているのがわかるはずです。まず1点はuserの表示が増えたこと、そしてmaskという新しい項目ができたことです。maskは所有するユーザ以外に与えることのできる最大限の権限です。この場合はmaskに対して指定していないのでデフォルトの&amp;quot;r&amp;quot;が設定されています。&lt;br /&gt;
ここではwww-dataのみですが、複数のユーザに対しても同様に個別の設定をすることができます。&lt;br /&gt;
ここではユーザのみに関して説明していますが、グループに対しても複数のグループを割り当てたりすることが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さらに詳しく知るためには&lt;br /&gt;
openSUSE&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 20 Linux でのアクセス制御リスト&lt;br /&gt;
https://www.belbel.or.jp/opensuse-manuals_ja/cha-security-acls.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
やRadHat&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
システム管理者のガイド 第5章 アクセス制御リスト&lt;br /&gt;
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-access_control_lists&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
などのACLに関する運用ドキュメントが参考になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、この状態でls -lでファイルのパーミッションの状況をみてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % ls -l foo.txt&lt;br /&gt;
 -rw-r-----+ 1 hironobu hironobu 0 Aug 31 08:15 foo.txt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最後に&amp;quot;+&amp;quot;と表示されているのは、ACLが設定されているということを意味しています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL: &lt;br /&gt;
http://uc2.h2np.net/i/df.html&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86&amp;diff=1723</id>
		<title>記憶管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86&amp;diff=1723"/>
		<updated>2022-05-29T08:14:30Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* zswap */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 実メモリ ==&lt;br /&gt;
&lt;br /&gt;
まず混乱を避けるためにメモリというあまりにも普段使い慣れた言葉を明確にしましょう。この節で使うメモリという言葉は、ハードウェア部品のメモリのことではなく、オペレーティングシステムが管理し参照できる主記憶や仮想記憶もすべて含めた記憶領域の意味です。ですから、ここでのメモリという言葉は概念的でもあり、また実際に存在するものでもある両方の性質を持ちます。ここではハードウェアのメモリにあたるものとして実メモリという言葉を使います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
メモリは重要なリソースである上に、しかも注意深く管理しなければならない&lt;br /&gt;
ものであるのは、いまさら言うまでもありません。メモリ上に実行コードやデー&lt;br /&gt;
タが展開されていて、それに対し正しいアクセス制御できなければシステムは&lt;br /&gt;
正常に動かなくなってしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリはいうまでもなく限定された貴重な資源です。実メモリはプログラムが使うだけでなく、I/Oのキャッシュに使ってI/Oパフォーマンスを改善することにも使います。&lt;br /&gt;
もしプログラムの中で既にアクセスされないメモリ空間を実メモリにかかえていていて、実メモリをキャッシュに使えないような場合は、せっかくの実メモリが有効に使えていない状態になってしまいます。&lt;br /&gt;
そこでプログラムが抱えたまま使っていないメモリ空間を外部記憶装置に送り出し、その分の実メモリをI/Oのキャッシュに利用するならば、全体のパフォーマンスが向上するはずです。このようにプログラムに使うメモリ空間を管理するだけでなくシステム全体を通して実メモリを有効に使うことが重要になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ページ ====&lt;br /&gt;
&lt;br /&gt;
[[File:Memory_fig1.png|thumb|right|300px|シンプルなアクセスモデル]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスからアクセスできるメモリリソースを考えてみましょう。&lt;br /&gt;
単純なモデルにしてみると右図のようにCPUリソースからメモリリソースに対しアクセスし読み書きする形になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、みなさんは今時の記憶管理はこのような単純なモデルではなく、物理的なメモリサイズよりも大きなメモリ空間を扱える仮想記憶があることは既に承知しているはずです。&lt;br /&gt;
仮想記憶はメモリ空間をページと呼ばれる一定サイズのフレーム（区分）にし、&lt;br /&gt;
そのページをハードディスクのような外部記憶装置と物理的なメモリである実メモリ間で書き出し、&lt;br /&gt;
読み込みを行うことによって、&lt;br /&gt;
実際の実メモリの容量よりも多くのメモリ空間を使えるようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この書き込みや読み込みをする単位をページと呼びます。扱えるページのサイズはCPU依存&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
これらはCPUのアーキテクチャーに依存するので異なる場合があります。例えばIBM POWER5+ や POWER6 プロセッサーは64KBのページサイズも利用することが出来ます。&lt;br /&gt;
&lt;br /&gt;
([https://www.ibm.com/support/knowledgecenter/ssw_aix_72/performance/multiple_page_size_support.html Multiple page size support])&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
x86-64(Intel 64)アーキテクチャーの場合2MBと1GBの拡大したページサイズが使えます。&lt;br /&gt;
([https://software.intel.com/sites/default/files/managed/a4/60/325384-sdm-vol-3abcd.pdf Intel 64 and IA-32 Architectures Software Developer’s Manual])&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ですが、多くのCPUの最小ページサイズが4KBなのでLinuxのページサイズはデフォルトで4KBとなっています。&lt;br /&gt;
&lt;br /&gt;
==== MMU ====&lt;br /&gt;
&lt;br /&gt;
[[File:Memory_fig2.png|thumb|left|300px|仮想記憶のモデル]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスに割り当てられているメモリリソースとしてのメモリのアドレスは仮想的なアドレス空間に割り当てられます。仮想アドレス空間での仮想アドレスは、実際の実メモリの物理的な意味でのアドレスとは一致しません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
仮想アドレス空間と実メモリアドレス空間のマッピングは、それを管理する MMU (Memory Management Unit) というハードウェアによってマップされています。&lt;br /&gt;
今時はMMU はCPUチップ上に組み込まれていますが、概念的にはCPUとは違うハードウェアです。&lt;br /&gt;
むかしはCPUの中に入っていなかったので、CPUとは別にMMUのチップ&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
MC68851: paged memory management unit user&#039;s manual (1986) [http://portal.acm.org/citation.cfm?id=16723]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を用意していました。&lt;br /&gt;
また広大なメモリ空間を必要としない組込み用途向けCPUにはMMUを持っていないものもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスは仮想アドレス空間にアクセスしています。&lt;br /&gt;
MMU がアドレス変換をして仮想アドレス空間より実メモリアドレス空間をマップしてくれています。&lt;br /&gt;
これによってプロセスが連続したメモリ空間を確保することができるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリに入りきらないものを外部記憶装置に書き出し、必要になったら実メモリに読み込もうというのが仮想記憶です。&lt;br /&gt;
実メモリアドレス空間より仮想アドレス空間よりが大きい状態になっていれば、実メモリ上にない仮想アドレスを要求することが発生します。&lt;br /&gt;
例えば32ビットアーキテクチャーの場合(2&amp;lt;sup&amp;gt;32&amp;lt;/sup&amp;gt; / 4GB  ) は仮想記憶空間として1048576(2&amp;lt;sup&amp;gt;20&amp;lt;/sup&amp;gt;)のページを持つことになります。&amp;lt;ref&amp;gt;IA-32アーキテクチャで物理アドレス拡張(PAE)を使うことはひとまずおいておきます。&amp;lt;/ref&amp;gt;もし512MBの物理メモリしか搭載していないマシンは内部で131072ページしか持っていません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
アクセス時はアドレス変換を行うためのキャッシュであるTLB (Translation Lookaside Buffer)にアドレスを問い合わせます。&lt;br /&gt;
MMUの中にTLBの機能が含まれているタイプ、あるいはCPUチップ上にMMUとは別にTLBを用意しているタイプなどがあります。&lt;br /&gt;
いずれにしてもTLBにアドレスが見つからなかった場合、つまり実メモリ上に該当ページを見つけられないとMMUはシグナルを発生させます。&lt;br /&gt;
これをページフォルトいいます。&lt;br /&gt;
&lt;br /&gt;
== ページング ==&lt;br /&gt;
=== ページフォルト === &lt;br /&gt;
[[File:Memory_fig3.png|thumb|right|300px|ページフォルト時のモデル]]&lt;br /&gt;
ページフォルト（Page Fault）の発生をうけてオペレーティングシステムは実メモリ上に必要な記憶領域を確保しようとします。&lt;br /&gt;
実メモリのサイズは限られているわけですから、&lt;br /&gt;
必要であれば実メモリのページ内容を外部記憶装置に書き出し、&lt;br /&gt;
空きを作りそこに新しいページをマッピングします。&lt;br /&gt;
再度、その外部に書き出されたページをアクセスすることが発生したら、&lt;br /&gt;
該当のページを外部記憶装置から実メモリ上に読み込んできます。&lt;br /&gt;
ページを読み込むのがページイン (page-in)、&lt;br /&gt;
ページを書き出すのはページアウト(page-out)といいます。&lt;br /&gt;
&lt;br /&gt;
=== スワップ === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
仮想記憶で実メモリ上からハードディスクなどの補助記憶装置との間でメモリの内容を書き出したり、読み込んだりするメカニズムことをスワップ(交換)といいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
厳密にいえば本来のスワップの定義はメモリが少なくなるとプロセスが使っているメモリをまるごと補助記憶装置に移動させる方法です。&lt;br /&gt;
ページングはページ単位ですからページングとスワップとは技術的には区別されます。&lt;br /&gt;
その意味でLinuxはページングだけやってスワップはしません。&amp;lt;ref&amp;gt; ちなみにソースコードmm/memory.cを見るとLinuxで仮想記憶が動き始めたのは1991年12月18日だそうです。mm/memory.c&amp;lt;/ref&amp;gt;&lt;br /&gt;
尚、 GNU/Linux 関連のドキュメントを読んでいると、&lt;br /&gt;
あまりスワップとページングの言葉の使い分けを明確に区別しているよう感じではなく、&lt;br /&gt;
仮想記憶でページング(paging)機能全体をざっくり指してスワップみたいな括りで呼んでいるような印象です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: 本来のスワップを持っているオペレーティングシステムには、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: スワップの具体的な運用に関する私見 [[スワップの運用について考えてみる]]&lt;br /&gt;
&lt;br /&gt;
=== Linuxのスワップ === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ですがLinuxはスワップという言葉を使っています。ここでは「ページをスワップ（交換）している」と解釈するしかないので、そういうことで話を進めます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、先ほど説明したように記憶空間はページと呼ばれる単位で分割されています。主記憶と補助記憶とのやりとりはページ単位で行われ、ページイン、ページアウトを行います。一般的にはハードディスク上にスワップ用のパーティションを取って、そこをスワップ先に指定します。多くの場合はインストール時にセットアップするようになっています。通常はパーティションをマウントするための情報を書く/etc/fstabにスワップパーティションの割り当ての記述が作られているはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  /dev/hda3 none  swap  sw,pri=0  0    0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
スワップの状態は/proc/swapsを見るとわかります。下の例はサイズが1453872K (1.45GB)バイトである/dev/hda3パーティションがスワップに使われているという意味です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cat /proc/swaps&lt;br /&gt;
 Filename       Type           Size    Used    Priority&lt;br /&gt;
 /dev/hda3      partition      1453872 0       -1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スワップ先はディスクパーティションだけではなく、通常のファイルでもスワップ先にできます。適当なサイズのファイルを作り、そのファイルをmkswapコマンドで処理し、最後にswaponコマンドでスワップに追加すると簡単に新しいスワップ領域が出来ます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== swapon ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばswapf01という名前のスワップファイルを作ってシステムにスワップファイルとして登録する時は次のようにします。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # /bin/dd if=/dev/zero of=swapf01 bs=8192 count=256&lt;br /&gt;
 # /sbin/mkswap swapf01 2048&lt;br /&gt;
 # sync &lt;br /&gt;
 # swapon swapf0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずswapf01を適当なサイズにして作成します。40KB以上、127MB以下ならいずれのサイズでも構いません。次に作ったファイルのサイズを1024で割った値をmkswapで指定するブロックサイズとします。mkswapが済んだならsyncしてからファイルをswaponします。ここではコマンドswaponを使っていますが、システムコールswapon()も用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どのファイルはハードディスクのパーティションであっても構いません。複数のハードディスクを同時に利用している時、スワップファイルを各々のハードディスク上に設定しスワップのプライオリティを同じ値にすることで、スワップディスクへの読み込み／書き込みなどディスクI/Oが分散させることができます。これはraid0のような効果となり高速化することになります。プライオリティを指定して、例えば高速なハードディスク、あるいはスワップファイルアクセス時にディスクスラッシングを避けるために作業しているハードディスクとは物理的に別のハードディスクをアクセスするようにするなどといったことも可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux 2.6.32でスワップについて試したことのメモランダム [[linuxのswapについて私が知っている二、三の事柄]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== zswap ====&lt;br /&gt;
&lt;br /&gt;
zswap[https://www.kernel.org/doc/Documentation/vm/zswap.txt]は、 Linux kernel version 3.15 から入った仮想メモリ圧縮 (Virtual Memory Compression)を利用したスワップで、外部記憶装置にページをスワップするのではなく、実メモリ上に作った圧縮ブロックデバイスにページをスワップする機能でです。実メモリ上にスワップできなくなった時に、これまでのスワップ機能で用意しているスワップ領域にスワップを始めます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ディスクなどメモリから比較すると低速なストレージへのI/Oが少なくなるため、頻繁にページアウトが発生しスワップファイルへのI/Oがボトルネックになるようなケースでは有用な機能です。フラッシュメモリを使ったSSDのような書き換え上限があるような外部記憶装置上にスワップファイルを作ると頻繁なスワップはメディアの劣化が進むためzswapが有効であるという議論もあります。圧縮処理が行われるため、その分、CPUに負荷がかかります。ただし、それがI/Oのオーバーヘッドによる処理の低下と比較し、相対的にどちらに利益があるかは、個々のシステム構成によって変化する議論であることは注意してください。&lt;br /&gt;
&lt;br /&gt;
== 局所参照性 ==&lt;br /&gt;
[[File:Memory_fig4.png|thumb|left|300px|キャッシュのモデル]]&lt;br /&gt;
&lt;br /&gt;
局所参照性とは「プログラムは同じ場所を繰り返しアクセスする性質を持ちやすい」というものです。&lt;br /&gt;
常に成立するわけではありません。&lt;br /&gt;
もしプログラムがランダムにメモリ空間全域をアクセスする性質を一般に持っていたならば、&lt;br /&gt;
たぶん仮想記憶のようなシステムは無意味だったでしょう。&lt;br /&gt;
なぜならば大量のページイン・ページアウトが発生しまうからです。&lt;br /&gt;
このように大量のページイン・ページアウトが発生してしまう状態をスラッシングと呼びます。&lt;br /&gt;
しかし殆んどのプログラムは局所参照性を持つので、&lt;br /&gt;
使われていない部分を外部に移しても全体としてみた場合、&lt;br /&gt;
リーズナブルなパフォーマンスが得られています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この考え方は仮想記憶に限らずCPUのキャッシュメモリなどでも使われています。&lt;br /&gt;
最近のCPUはキャッシュが512KB、1MB、2MB という具合にどんどん増えています。&lt;br /&gt;
これはメモリからデータをフェッチしてきて、CPU内のキャッシュにおき、そこをアクセスすることで高速化を狙います。&lt;br /&gt;
当然、外にあるメモリよりCPU内のキャッシュの方がアクセス速度は格段に良いですから、それだけ速度が出るということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これを一般化してみると、&lt;br /&gt;
「データを高速にアクセスできるほど装置は容量当たりのコストが高いので、&#039;&#039;&#039;容量とコストを勘案し多段に装置を組合せることによって、リーズナブルに高速で大容量のアクセスできる記憶装置を用意&#039;&#039;&#039;することができる」&lt;br /&gt;
ということがいえるでしょう。&lt;br /&gt;
メモリ、仮想記憶、ファイルシステムなど色々な場面でこの考え方が現れます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このアクセスが高速で小容量の装置と低速で大容量の装置との間でデータを移動させなければなりませんが、&lt;br /&gt;
この時どのデータを選ぶかが問題になってきます。&lt;br /&gt;
よく使われるデータは速い方へ、なかなか使われないデータは遅い方へ移すのが合理的です。&lt;br /&gt;
ただし、「良く使われる」というのは過去の話ではなく将来の話だという所がポイントです。&lt;br /&gt;
「良く使われるだろう」と判断するルールを決めなければなりません。&lt;br /&gt;
このルールでよく使われるのがLRU (least recently used)です。LRUは直訳すると「最近、最も使われていないもの」ということで、&lt;br /&gt;
簡単に言えば一番暇なものを入れ換えるという単純な話です。LinuxのページングもLRUのポリシーで行っています。&lt;br /&gt;
&lt;br /&gt;
== 動的なメモリ領域確保 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセス実行時に動的にメモリを確保するのにはプログラム中でmalloc(3)&amp;lt;ref&amp;gt; malloc(3)の3の意味はマニュアルの分類を示しています。&amp;lt;/ref&amp;gt;&lt;br /&gt;
を呼び出します。次のプログラムはプロセスが動的に512MBのメモリを割り当てるプログラムです。ここで使っているmalloc(3)やfree(3)の説明はオンラインマニュアルを参考してもらうとして、まずはプロセスが動的にメモリを確保するとどうなるかやってみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* プログラム: malloctest.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;C&#039; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
main()&lt;br /&gt;
{&lt;br /&gt;
  char *p;&lt;br /&gt;
  size_t  areasize=1024*1024*512;&lt;br /&gt;
  if ((p=(char *)malloc(areasize)) == NULL) {&lt;br /&gt;
    perror(&amp;quot;malloc&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  sleep(10);&lt;br /&gt;
  free(p);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*  実行例&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cc malloctest.c &lt;br /&gt;
 $ ./a.out &amp;amp;&lt;br /&gt;
 $ ps axu | grep a.out&lt;br /&gt;
 hironobu 29813  0.0  0.0 525528 284 pts/8    S    17:32   0:00 ./a.out&lt;br /&gt;
 ---この並びは下の様になっています---&lt;br /&gt;
 USER      PID  %CPU  %MEM   VSZ RSS TTY      STAT START   TIME COMMAND&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このプログラムは512MBメモリ領域をmalloc(3)を使いアロケーションしています。実行時の状況をpsで見てみると、VSZが525528、RSSが284となっています。VSZはVirtual memory Sizeのことで仮想記憶もふくめて全部のメモリサイズです。RSSはReal Set Sizeのことで、実メモリ(物理的なメモリ)で専有しているメモリサイズです。つまり、このプログラムは約523.5MBもの記憶領域を取っているにもかかわらず、実際の実メモリ上では284KBしか取られていません。 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: もしmallocが失敗した場合、malloc: xxxxというメッセージが出ます。その場合でも小さい数字にはなりますがVSZやRSSの値は出ているはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリ上にあるのは、現在使おうとしているメモリです。アクセスがまったく発生すらしていないページは、まだページインされていない状態と同じです。この初期状態の時はまだ何も存在していないので、ページアウトしたものをページインする動作にはなりません。ここの部分だけに着目すると、アクセス時には、そのまま実メモリに作られる形になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラム中のsleepのある行を除いて、コンパイルし実行すると見かけ上512MB以上ものメモリを消費するプログラムがであっても、一瞬でプログラムが終ります。なぜならば、512MBのメモリ空間にアクセスしていないので、見かけ上このサイズのメモリが取れていてもまだ存在していないからです。アクセスが発生した始めて実メモリ上に必要な領域が生成されます。このように大量のメモリを見かけ上確保しても、それを使わない限り仮想のままで終ります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次の ps コマンドを実行してみましょう。するとRSSでソートされて、USER / COMMAND / RSS / VSZの順で表示されます。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps -Ao user,args,rss,vsize --sort rss&lt;br /&gt;
 USER     COMMAND                        RSS   VSZ&lt;br /&gt;
 root     [keventd]                       0     0&lt;br /&gt;
 root     [ksoftirqd_CPU0]                0     0&lt;br /&gt;
 ...&lt;br /&gt;
 hironobu /usr/bin/emacs23            15732  42140&lt;br /&gt;
 hironobu gedit                       23204  173232&lt;br /&gt;
 hironobu /opt/google/chrome/chrome - 107380 359600&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
keventdやksoftirqd_CPU0などRSSとVSZが両方0のものはカーネルレベルで動いているスレッドです。ここではユーザレベルのプロセスであるemacs23のメモリの使い方に着目しましょう。emacs20はRSSは15732KBで、仮想記憶も含めたサイズは42140KBです。多くの場合、十分に実メモリに余裕があっても、プロセス中で生成された記憶空間がすべて実メモリの上に載っているわけではありません。必要のあるもののみ実メモリ上にページインされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
使われていない分、実メモリが空くわけですから、その分を動的にデバイスなどへのキャッシュなどに割り当ています。そのキャッシュが大きければ大きいほど、全体のパフォーマンスはよくなります。実メモリが必要になればキャッシュに使っていた実メモリをプロセスに回します。これはLinuxだけの話ではなく、今日多くのオペレーティングシステムではこのように全体のパフォーマンスを上げるためにメモリを効率よく使うというメカニズムが取り込まれています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: vmstatで観察してみましょう。vmstatは仮想記憶のステータス観察するためのツールです。1秒毎に表示するオプションで動作させながら、先程のプログラムを改造し徐々に記憶を取るようなプログラムにして動かし、観察してみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % vmstat  1 &amp;lt;- 1秒毎に表示&lt;br /&gt;
  procs                  memory    swap        io    system         cpu&lt;br /&gt;
  r b w  swpd  free  buff cache  si  so   bi   bo   in   cs  us  sy  id&lt;br /&gt;
  0 0 0   624  3324 14868 61228   0   0    1    1    3    9   0   0   0&lt;br /&gt;
 ......&lt;br /&gt;
  4 0 0 28724  1120   412  2196 476 536  119  160  444  668  93   7   0&lt;br /&gt;
  2 1 0 29964  1140   368  2128 316 124   79  310  485  817  37   9  54&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== コピーオンライトとその実際 == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのカーネルではプロセスが親から引き継がれたメモリ領域や実行コードなどを引き継いでいても、そこに書き換えが発生するまで、実際のメモリ領域はとりません。書き込みがあって始めてメモリ領域を確保し、中身をコピーして別なものにします。このことをコピーオンライト(CoW: Copy on Write)といいます。このような仕組みにより、高速に新しいプロセスを生成したり、あるいはメモリの効率的な利用が出きるようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/proc/(プロセスid)/smapsは、カーネル内の該当プロセスのメモリ利用状況を表示するAPIです。それを使って実験したいと思います。&lt;br /&gt;
dashはDebian版軽量シェルでシステムのシェルスクリプトを実行するのに使われます。&lt;br /&gt;
さて、$$はシェル自身のプロセスidですので、/proc/$$/smapsとすると現在使っているシェルのメモリ利用状況がわかります。&lt;br /&gt;
注目するのは Shared_Clean と Private_Clean の値です。&lt;br /&gt;
Shared_Clean はシェアしているメモリです。&lt;br /&gt;
Private_Clean は自らのメモリです。&lt;br /&gt;
クリーンな、という意味は、まだそのページは変更されていない（書き込みがおこっていない）という意味です。&lt;br /&gt;
まず最初、dashを起動してdashシェル環境でメモリ利用状況をみます。&lt;br /&gt;
この時、引き継ぐものがないのでPrivate_Cleanが76kB (= Rssの値と同じ)、Shared_Cleanが0kBとなっています。&lt;br /&gt;
次にdashの中でさらにdashを起動します。つまり最初のdashが親プロセスとなった新しいdashです。&lt;br /&gt;
この上で両方の値をみるとPrivate_Cleanが0kB、Shared_Cleanが76kB(= Rssの値と同じ)となっています。&lt;br /&gt;
つまり、子プロセス側となったdashのメモリは、この時点ではシェアしているものを使っていることがわかります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ dash&lt;br /&gt;
 $ cat /proc/$$/smaps | head -9&lt;br /&gt;
 08048000-08060000 r-xp 00000000 08:01 4825       /bin/dash&lt;br /&gt;
 Size:                 96 kB&lt;br /&gt;
 Rss:                  76 kB&lt;br /&gt;
 Pss:                  76 kB&lt;br /&gt;
 Shared_Clean:          0 kB&lt;br /&gt;
 Shared_Dirty:          0 kB&lt;br /&gt;
 Private_Clean:        76 kB&lt;br /&gt;
 Private_Dirty:         0 kB&lt;br /&gt;
 Referenced:           76 kB&lt;br /&gt;
 $ dash&lt;br /&gt;
 $ cat /proc/$$/smaps | head -9&lt;br /&gt;
 08048000-08060000 r-xp 00000000 08:01 4825       /bin/dash&lt;br /&gt;
 Size:                 96 kB&lt;br /&gt;
 Rss:                  76 kB&lt;br /&gt;
 Pss:                  34 kB&lt;br /&gt;
 Shared_Clean:         76 kB&lt;br /&gt;
 Shared_Dirty:          0 kB&lt;br /&gt;
 Private_Clean:         0 kB&lt;br /&gt;
 Private_Dirty:         0 kB&lt;br /&gt;
 Referenced:           76 kB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mmap ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mmap(2)はファイルをメモリのように使うためのシステムコールです。mmapを使うことによってファイルとメモリの境目はなくなります。次のプログラムを見てください。これはファイルをオープンした後、ファイルの中身を文字型配列としてアクセスしています。readを使って読み込みをしているわけではありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* プログラムmmap.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;C&#039; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/mman.h&amp;gt;&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct stat st;&lt;br /&gt;
  char *p;&lt;br /&gt;
  int i;&lt;br /&gt;
  fd=open(&amp;quot;dat&amp;quot;,O_RDWR);&lt;br /&gt;
  fstat(fd, &amp;amp;st);&lt;br /&gt;
  p=mmap(0,st.st_size,(PROT_READ|PROT_WRITE),MAP_PRIVATE,fd,0);&lt;br /&gt;
  for(i=0; i &amp;lt; st.st_size; i++) {&lt;br /&gt;
    printf(&amp;quot;[%c]&amp;quot;,p[i]);&lt;br /&gt;
  }&lt;br /&gt;
  close(fd);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*  実行&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ echo -n &#039;abcdefg&#039; &amp;gt; dat&lt;br /&gt;
 $ cc mmap.c&lt;br /&gt;
 $ ./a.out&lt;br /&gt;
 [a][b][c][d][e][f][g]$ &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイルdatの中身は&amp;quot;abcdefg&amp;quot;となっています。datをオープンしfstatでファイルのステータス情報を取り出します。そのステータス情報の中のファイルサイズがst.st_sizeです。mmapを使って、ファイルdatの中身をメモリ空間として割り当てます。そのポインタがpです。ループ内でpの中身を表示させると、ファイルの内容と同じであることがわかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはメモリの中にファイルを読み込んでいるわけではありません。ファイルをメモリにマップしたのです。スワップページからページインするのと良く似ていると気が着く人もいるでしょうが、基本的には同じ動作で、ファイルを読み出す過程はページインと同じ仕組みです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これは今日のUNIX系オペレーティングシステムでの重要なメカニズムの一つです。たとえばLinuxではプログラムを実行する時、バイナリの実行ファイルや標準ライブラリを読み込む動作をするのではなくmmapでマップします。これでファイルシステムとは違う記憶領域であるはずのメモリ内に存在するのと、まったく同じ動作ができます。動作時に実行コードをページインします。&lt;br /&gt;
&lt;br /&gt;
glibcでのmalloc実装は/dev/zeroをオープンし一定領域をmmapで確保し、その領域から必要な分を切り出してプログラム側に返却しています。つまりmallocを呼び出したプログラムは/dev/zeroの領域を使っています。/dev/zeroは物理的なデバイスの実体を持たないので、カーネルが与えたメモリ空間になります。mmapはこんな使い方もされているという一例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、この例題プログラムではマップする属性をMAP_PRIVATEとしているので、ファイルの内容を読み込みはしますが、メモリ領域に書き込んでも、それはファイルには書き込まれません。これをMAP_SHAREDとするとファイルと同期を取ることができます。このファイルを複数のプログラムからオープンすると共有メモリとして利用できます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 内容をアップデートして同期するにはメモリに書き込み後、msync(2)やmunmap(2)を呼ぶことが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 単一レベル記憶 ===&lt;br /&gt;
&lt;br /&gt;
ファイルもメモリも、さらにデバイスすらも単純な1つの記憶空間として扱おうというコンセプトが単一レベル記憶です。&lt;br /&gt;
現在、オペレーティングシステムレベルでサポートしているのはIBM社のSystem iシリーズ&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
IBMのサイトにあるIBM System iの単一レベル記憶の解説 :  http://www-06.ibm.com/systems/jp/i/seminar/reconf/reconf1.shtml&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ぐらいしかないので、&lt;br /&gt;
インターネット上で説明を探すとIBM System iの機能＝単一レベル記憶の定義みたいな説明しかありませんが、&lt;br /&gt;
実は、その歴史は古く1960年代に作られたMultics上に既に実装&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Multics and More VM&lt;br /&gt;
https://users.cs.duke.edu/~chase/cps210-archive/slides/multics-vm.pdf&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXは単一レベル記憶を前提としているデザインはありませんが、現在のUNIX系のオペレーティングシステムはmmapを実装することによってファイルもメモリも、そしてデバイスも同様に扱うことができる利益を得ています。&lt;br /&gt;
例としては今時のLinuxやその他UNIX系のオペレーティングシステムでは実行バイナリやライブラリを動かすとき、一々ファイルの中身を読み込む動作をせず、実行するバイナリデータを内部でマップしてしまいます。&lt;br /&gt;
ですから古典的なUNIXで言われるような、「実行バイナリファイルをメモリに読み込み実行する」という表現は、少なくとも現在のLinuxの実行時の表現としては適切ではないという状況になっています。あとデバイスの利用例としては、malloc()のいくつかの実装&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
The GNU Allocator&lt;br /&gt;
https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
では内部で記憶領域を確保するとき/dev/zeroをmmapでオープンして使っています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86&amp;diff=1722</id>
		<title>記憶管理</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86&amp;diff=1722"/>
		<updated>2022-05-29T08:13:56Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* swapon */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 実メモリ ==&lt;br /&gt;
&lt;br /&gt;
まず混乱を避けるためにメモリというあまりにも普段使い慣れた言葉を明確にしましょう。この節で使うメモリという言葉は、ハードウェア部品のメモリのことではなく、オペレーティングシステムが管理し参照できる主記憶や仮想記憶もすべて含めた記憶領域の意味です。ですから、ここでのメモリという言葉は概念的でもあり、また実際に存在するものでもある両方の性質を持ちます。ここではハードウェアのメモリにあたるものとして実メモリという言葉を使います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
メモリは重要なリソースである上に、しかも注意深く管理しなければならない&lt;br /&gt;
ものであるのは、いまさら言うまでもありません。メモリ上に実行コードやデー&lt;br /&gt;
タが展開されていて、それに対し正しいアクセス制御できなければシステムは&lt;br /&gt;
正常に動かなくなってしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリはいうまでもなく限定された貴重な資源です。実メモリはプログラムが使うだけでなく、I/Oのキャッシュに使ってI/Oパフォーマンスを改善することにも使います。&lt;br /&gt;
もしプログラムの中で既にアクセスされないメモリ空間を実メモリにかかえていていて、実メモリをキャッシュに使えないような場合は、せっかくの実メモリが有効に使えていない状態になってしまいます。&lt;br /&gt;
そこでプログラムが抱えたまま使っていないメモリ空間を外部記憶装置に送り出し、その分の実メモリをI/Oのキャッシュに利用するならば、全体のパフォーマンスが向上するはずです。このようにプログラムに使うメモリ空間を管理するだけでなくシステム全体を通して実メモリを有効に使うことが重要になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ページ ====&lt;br /&gt;
&lt;br /&gt;
[[File:Memory_fig1.png|thumb|right|300px|シンプルなアクセスモデル]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスからアクセスできるメモリリソースを考えてみましょう。&lt;br /&gt;
単純なモデルにしてみると右図のようにCPUリソースからメモリリソースに対しアクセスし読み書きする形になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、みなさんは今時の記憶管理はこのような単純なモデルではなく、物理的なメモリサイズよりも大きなメモリ空間を扱える仮想記憶があることは既に承知しているはずです。&lt;br /&gt;
仮想記憶はメモリ空間をページと呼ばれる一定サイズのフレーム（区分）にし、&lt;br /&gt;
そのページをハードディスクのような外部記憶装置と物理的なメモリである実メモリ間で書き出し、&lt;br /&gt;
読み込みを行うことによって、&lt;br /&gt;
実際の実メモリの容量よりも多くのメモリ空間を使えるようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この書き込みや読み込みをする単位をページと呼びます。扱えるページのサイズはCPU依存&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
これらはCPUのアーキテクチャーに依存するので異なる場合があります。例えばIBM POWER5+ や POWER6 プロセッサーは64KBのページサイズも利用することが出来ます。&lt;br /&gt;
&lt;br /&gt;
([https://www.ibm.com/support/knowledgecenter/ssw_aix_72/performance/multiple_page_size_support.html Multiple page size support])&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
x86-64(Intel 64)アーキテクチャーの場合2MBと1GBの拡大したページサイズが使えます。&lt;br /&gt;
([https://software.intel.com/sites/default/files/managed/a4/60/325384-sdm-vol-3abcd.pdf Intel 64 and IA-32 Architectures Software Developer’s Manual])&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ですが、多くのCPUの最小ページサイズが4KBなのでLinuxのページサイズはデフォルトで4KBとなっています。&lt;br /&gt;
&lt;br /&gt;
==== MMU ====&lt;br /&gt;
&lt;br /&gt;
[[File:Memory_fig2.png|thumb|left|300px|仮想記憶のモデル]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスに割り当てられているメモリリソースとしてのメモリのアドレスは仮想的なアドレス空間に割り当てられます。仮想アドレス空間での仮想アドレスは、実際の実メモリの物理的な意味でのアドレスとは一致しません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
仮想アドレス空間と実メモリアドレス空間のマッピングは、それを管理する MMU (Memory Management Unit) というハードウェアによってマップされています。&lt;br /&gt;
今時はMMU はCPUチップ上に組み込まれていますが、概念的にはCPUとは違うハードウェアです。&lt;br /&gt;
むかしはCPUの中に入っていなかったので、CPUとは別にMMUのチップ&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
MC68851: paged memory management unit user&#039;s manual (1986) [http://portal.acm.org/citation.cfm?id=16723]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を用意していました。&lt;br /&gt;
また広大なメモリ空間を必要としない組込み用途向けCPUにはMMUを持っていないものもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセスは仮想アドレス空間にアクセスしています。&lt;br /&gt;
MMU がアドレス変換をして仮想アドレス空間より実メモリアドレス空間をマップしてくれています。&lt;br /&gt;
これによってプロセスが連続したメモリ空間を確保することができるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリに入りきらないものを外部記憶装置に書き出し、必要になったら実メモリに読み込もうというのが仮想記憶です。&lt;br /&gt;
実メモリアドレス空間より仮想アドレス空間よりが大きい状態になっていれば、実メモリ上にない仮想アドレスを要求することが発生します。&lt;br /&gt;
例えば32ビットアーキテクチャーの場合(2&amp;lt;sup&amp;gt;32&amp;lt;/sup&amp;gt; / 4GB  ) は仮想記憶空間として1048576(2&amp;lt;sup&amp;gt;20&amp;lt;/sup&amp;gt;)のページを持つことになります。&amp;lt;ref&amp;gt;IA-32アーキテクチャで物理アドレス拡張(PAE)を使うことはひとまずおいておきます。&amp;lt;/ref&amp;gt;もし512MBの物理メモリしか搭載していないマシンは内部で131072ページしか持っていません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
アクセス時はアドレス変換を行うためのキャッシュであるTLB (Translation Lookaside Buffer)にアドレスを問い合わせます。&lt;br /&gt;
MMUの中にTLBの機能が含まれているタイプ、あるいはCPUチップ上にMMUとは別にTLBを用意しているタイプなどがあります。&lt;br /&gt;
いずれにしてもTLBにアドレスが見つからなかった場合、つまり実メモリ上に該当ページを見つけられないとMMUはシグナルを発生させます。&lt;br /&gt;
これをページフォルトいいます。&lt;br /&gt;
&lt;br /&gt;
== ページング ==&lt;br /&gt;
=== ページフォルト === &lt;br /&gt;
[[File:Memory_fig3.png|thumb|right|300px|ページフォルト時のモデル]]&lt;br /&gt;
ページフォルト（Page Fault）の発生をうけてオペレーティングシステムは実メモリ上に必要な記憶領域を確保しようとします。&lt;br /&gt;
実メモリのサイズは限られているわけですから、&lt;br /&gt;
必要であれば実メモリのページ内容を外部記憶装置に書き出し、&lt;br /&gt;
空きを作りそこに新しいページをマッピングします。&lt;br /&gt;
再度、その外部に書き出されたページをアクセスすることが発生したら、&lt;br /&gt;
該当のページを外部記憶装置から実メモリ上に読み込んできます。&lt;br /&gt;
ページを読み込むのがページイン (page-in)、&lt;br /&gt;
ページを書き出すのはページアウト(page-out)といいます。&lt;br /&gt;
&lt;br /&gt;
=== スワップ === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
仮想記憶で実メモリ上からハードディスクなどの補助記憶装置との間でメモリの内容を書き出したり、読み込んだりするメカニズムことをスワップ(交換)といいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
厳密にいえば本来のスワップの定義はメモリが少なくなるとプロセスが使っているメモリをまるごと補助記憶装置に移動させる方法です。&lt;br /&gt;
ページングはページ単位ですからページングとスワップとは技術的には区別されます。&lt;br /&gt;
その意味でLinuxはページングだけやってスワップはしません。&amp;lt;ref&amp;gt; ちなみにソースコードmm/memory.cを見るとLinuxで仮想記憶が動き始めたのは1991年12月18日だそうです。mm/memory.c&amp;lt;/ref&amp;gt;&lt;br /&gt;
尚、 GNU/Linux 関連のドキュメントを読んでいると、&lt;br /&gt;
あまりスワップとページングの言葉の使い分けを明確に区別しているよう感じではなく、&lt;br /&gt;
仮想記憶でページング(paging)機能全体をざっくり指してスワップみたいな括りで呼んでいるような印象です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: 本来のスワップを持っているオペレーティングシステムには、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: スワップの具体的な運用に関する私見 [[スワップの運用について考えてみる]]&lt;br /&gt;
&lt;br /&gt;
=== Linuxのスワップ === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ですがLinuxはスワップという言葉を使っています。ここでは「ページをスワップ（交換）している」と解釈するしかないので、そういうことで話を進めます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、先ほど説明したように記憶空間はページと呼ばれる単位で分割されています。主記憶と補助記憶とのやりとりはページ単位で行われ、ページイン、ページアウトを行います。一般的にはハードディスク上にスワップ用のパーティションを取って、そこをスワップ先に指定します。多くの場合はインストール時にセットアップするようになっています。通常はパーティションをマウントするための情報を書く/etc/fstabにスワップパーティションの割り当ての記述が作られているはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  /dev/hda3 none  swap  sw,pri=0  0    0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
スワップの状態は/proc/swapsを見るとわかります。下の例はサイズが1453872K (1.45GB)バイトである/dev/hda3パーティションがスワップに使われているという意味です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % cat /proc/swaps&lt;br /&gt;
 Filename       Type           Size    Used    Priority&lt;br /&gt;
 /dev/hda3      partition      1453872 0       -1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
スワップ先はディスクパーティションだけではなく、通常のファイルでもスワップ先にできます。適当なサイズのファイルを作り、そのファイルをmkswapコマンドで処理し、最後にswaponコマンドでスワップに追加すると簡単に新しいスワップ領域が出来ます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== swapon ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばswapf01という名前のスワップファイルを作ってシステムにスワップファイルとして登録する時は次のようにします。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 # /bin/dd if=/dev/zero of=swapf01 bs=8192 count=256&lt;br /&gt;
 # /sbin/mkswap swapf01 2048&lt;br /&gt;
 # sync &lt;br /&gt;
 # swapon swapf0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
まずswapf01を適当なサイズにして作成します。40KB以上、127MB以下ならいずれのサイズでも構いません。次に作ったファイルのサイズを1024で割った値をmkswapで指定するブロックサイズとします。mkswapが済んだならsyncしてからファイルをswaponします。ここではコマンドswaponを使っていますが、システムコールswapon()も用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どのファイルはハードディスクのパーティションであっても構いません。複数のハードディスクを同時に利用している時、スワップファイルを各々のハードディスク上に設定しスワップのプライオリティを同じ値にすることで、スワップディスクへの読み込み／書き込みなどディスクI/Oが分散させることができます。これはraid0のような効果となり高速化することになります。プライオリティを指定して、例えば高速なハードディスク、あるいはスワップファイルアクセス時にディスクスラッシングを避けるために作業しているハードディスクとは物理的に別のハードディスクをアクセスするようにするなどといったことも可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: Linux 2.6.32でスワップについて試したことのメモランダム [[linuxのswapについて私が知っている二、三の事柄]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== zswap ====&lt;br /&gt;
&lt;br /&gt;
zswap[https://www.kernel.org/doc/Documentation/vm/zswap.txt]は、 Linux kernel version 3.15 から入った仮想メモリ圧縮 (Virtual Memory Compression)を利用したスワップで、外部記憶装置にページをスワップするのではなく、実メモリ上に作った圧縮ブロックデバイスにページをスワップする機能でです。実メモリ上にスワップできなくなった時に、これまでのスワップ機能で用意しているスワップ領域にスワップを始めます。&lt;br /&gt;
&lt;br /&gt;
ディスクなどメモリから比較すると低速なストレージへのI/Oが少なくなるため、頻繁にページアウトが発生しスワップファイルへのI/Oがボトルネックになるようなケースでは有用な機能です。フラッシュメモリを使ったSSDのような書き換え上限があるような外部記憶装置上にスワップファイルを作ると頻繁なスワップはメディアの劣化が進むためzswapが有効であるという議論もあります。圧縮処理が行われるため、その分、CPUに負荷がかかります。ただし、それがI/Oのオーバーヘッドによる処理の低下と比較し、相対的にどちらに利益があるかは、個々のシステム構成によって変化する議論であることは注意してください。&lt;br /&gt;
&lt;br /&gt;
== 局所参照性 ==&lt;br /&gt;
[[File:Memory_fig4.png|thumb|left|300px|キャッシュのモデル]]&lt;br /&gt;
&lt;br /&gt;
局所参照性とは「プログラムは同じ場所を繰り返しアクセスする性質を持ちやすい」というものです。&lt;br /&gt;
常に成立するわけではありません。&lt;br /&gt;
もしプログラムがランダムにメモリ空間全域をアクセスする性質を一般に持っていたならば、&lt;br /&gt;
たぶん仮想記憶のようなシステムは無意味だったでしょう。&lt;br /&gt;
なぜならば大量のページイン・ページアウトが発生しまうからです。&lt;br /&gt;
このように大量のページイン・ページアウトが発生してしまう状態をスラッシングと呼びます。&lt;br /&gt;
しかし殆んどのプログラムは局所参照性を持つので、&lt;br /&gt;
使われていない部分を外部に移しても全体としてみた場合、&lt;br /&gt;
リーズナブルなパフォーマンスが得られています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この考え方は仮想記憶に限らずCPUのキャッシュメモリなどでも使われています。&lt;br /&gt;
最近のCPUはキャッシュが512KB、1MB、2MB という具合にどんどん増えています。&lt;br /&gt;
これはメモリからデータをフェッチしてきて、CPU内のキャッシュにおき、そこをアクセスすることで高速化を狙います。&lt;br /&gt;
当然、外にあるメモリよりCPU内のキャッシュの方がアクセス速度は格段に良いですから、それだけ速度が出るということになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これを一般化してみると、&lt;br /&gt;
「データを高速にアクセスできるほど装置は容量当たりのコストが高いので、&#039;&#039;&#039;容量とコストを勘案し多段に装置を組合せることによって、リーズナブルに高速で大容量のアクセスできる記憶装置を用意&#039;&#039;&#039;することができる」&lt;br /&gt;
ということがいえるでしょう。&lt;br /&gt;
メモリ、仮想記憶、ファイルシステムなど色々な場面でこの考え方が現れます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このアクセスが高速で小容量の装置と低速で大容量の装置との間でデータを移動させなければなりませんが、&lt;br /&gt;
この時どのデータを選ぶかが問題になってきます。&lt;br /&gt;
よく使われるデータは速い方へ、なかなか使われないデータは遅い方へ移すのが合理的です。&lt;br /&gt;
ただし、「良く使われる」というのは過去の話ではなく将来の話だという所がポイントです。&lt;br /&gt;
「良く使われるだろう」と判断するルールを決めなければなりません。&lt;br /&gt;
このルールでよく使われるのがLRU (least recently used)です。LRUは直訳すると「最近、最も使われていないもの」ということで、&lt;br /&gt;
簡単に言えば一番暇なものを入れ換えるという単純な話です。LinuxのページングもLRUのポリシーで行っています。&lt;br /&gt;
&lt;br /&gt;
== 動的なメモリ領域確保 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プロセス実行時に動的にメモリを確保するのにはプログラム中でmalloc(3)&amp;lt;ref&amp;gt; malloc(3)の3の意味はマニュアルの分類を示しています。&amp;lt;/ref&amp;gt;&lt;br /&gt;
を呼び出します。次のプログラムはプロセスが動的に512MBのメモリを割り当てるプログラムです。ここで使っているmalloc(3)やfree(3)の説明はオンラインマニュアルを参考してもらうとして、まずはプロセスが動的にメモリを確保するとどうなるかやってみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* プログラム: malloctest.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;C&#039; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
 #include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
main()&lt;br /&gt;
{&lt;br /&gt;
  char *p;&lt;br /&gt;
  size_t  areasize=1024*1024*512;&lt;br /&gt;
  if ((p=(char *)malloc(areasize)) == NULL) {&lt;br /&gt;
    perror(&amp;quot;malloc&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  sleep(10);&lt;br /&gt;
  free(p);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*  実行例&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cc malloctest.c &lt;br /&gt;
 $ ./a.out &amp;amp;&lt;br /&gt;
 $ ps axu | grep a.out&lt;br /&gt;
 hironobu 29813  0.0  0.0 525528 284 pts/8    S    17:32   0:00 ./a.out&lt;br /&gt;
 ---この並びは下の様になっています---&lt;br /&gt;
 USER      PID  %CPU  %MEM   VSZ RSS TTY      STAT START   TIME COMMAND&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このプログラムは512MBメモリ領域をmalloc(3)を使いアロケーションしています。実行時の状況をpsで見てみると、VSZが525528、RSSが284となっています。VSZはVirtual memory Sizeのことで仮想記憶もふくめて全部のメモリサイズです。RSSはReal Set Sizeのことで、実メモリ(物理的なメモリ)で専有しているメモリサイズです。つまり、このプログラムは約523.5MBもの記憶領域を取っているにもかかわらず、実際の実メモリ上では284KBしか取られていません。 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: もしmallocが失敗した場合、malloc: xxxxというメッセージが出ます。その場合でも小さい数字にはなりますがVSZやRSSの値は出ているはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実メモリ上にあるのは、現在使おうとしているメモリです。アクセスがまったく発生すらしていないページは、まだページインされていない状態と同じです。この初期状態の時はまだ何も存在していないので、ページアウトしたものをページインする動作にはなりません。ここの部分だけに着目すると、アクセス時には、そのまま実メモリに作られる形になります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
プログラム中のsleepのある行を除いて、コンパイルし実行すると見かけ上512MB以上ものメモリを消費するプログラムがであっても、一瞬でプログラムが終ります。なぜならば、512MBのメモリ空間にアクセスしていないので、見かけ上このサイズのメモリが取れていてもまだ存在していないからです。アクセスが発生した始めて実メモリ上に必要な領域が生成されます。このように大量のメモリを見かけ上確保しても、それを使わない限り仮想のままで終ります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
次の ps コマンドを実行してみましょう。するとRSSでソートされて、USER / COMMAND / RSS / VSZの順で表示されます。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps -Ao user,args,rss,vsize --sort rss&lt;br /&gt;
 USER     COMMAND                        RSS   VSZ&lt;br /&gt;
 root     [keventd]                       0     0&lt;br /&gt;
 root     [ksoftirqd_CPU0]                0     0&lt;br /&gt;
 ...&lt;br /&gt;
 hironobu /usr/bin/emacs23            15732  42140&lt;br /&gt;
 hironobu gedit                       23204  173232&lt;br /&gt;
 hironobu /opt/google/chrome/chrome - 107380 359600&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
keventdやksoftirqd_CPU0などRSSとVSZが両方0のものはカーネルレベルで動いているスレッドです。ここではユーザレベルのプロセスであるemacs23のメモリの使い方に着目しましょう。emacs20はRSSは15732KBで、仮想記憶も含めたサイズは42140KBです。多くの場合、十分に実メモリに余裕があっても、プロセス中で生成された記憶空間がすべて実メモリの上に載っているわけではありません。必要のあるもののみ実メモリ上にページインされます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
使われていない分、実メモリが空くわけですから、その分を動的にデバイスなどへのキャッシュなどに割り当ています。そのキャッシュが大きければ大きいほど、全体のパフォーマンスはよくなります。実メモリが必要になればキャッシュに使っていた実メモリをプロセスに回します。これはLinuxだけの話ではなく、今日多くのオペレーティングシステムではこのように全体のパフォーマンスを上げるためにメモリを効率よく使うというメカニズムが取り込まれています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう: vmstatで観察してみましょう。vmstatは仮想記憶のステータス観察するためのツールです。1秒毎に表示するオプションで動作させながら、先程のプログラムを改造し徐々に記憶を取るようなプログラムにして動かし、観察してみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % vmstat  1 &amp;lt;- 1秒毎に表示&lt;br /&gt;
  procs                  memory    swap        io    system         cpu&lt;br /&gt;
  r b w  swpd  free  buff cache  si  so   bi   bo   in   cs  us  sy  id&lt;br /&gt;
  0 0 0   624  3324 14868 61228   0   0    1    1    3    9   0   0   0&lt;br /&gt;
 ......&lt;br /&gt;
  4 0 0 28724  1120   412  2196 476 536  119  160  444  668  93   7   0&lt;br /&gt;
  2 1 0 29964  1140   368  2128 316 124   79  310  485  817  37   9  54&lt;br /&gt;
 ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== コピーオンライトとその実際 == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxのカーネルではプロセスが親から引き継がれたメモリ領域や実行コードなどを引き継いでいても、そこに書き換えが発生するまで、実際のメモリ領域はとりません。書き込みがあって始めてメモリ領域を確保し、中身をコピーして別なものにします。このことをコピーオンライト(CoW: Copy on Write)といいます。このような仕組みにより、高速に新しいプロセスを生成したり、あるいはメモリの効率的な利用が出きるようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/proc/(プロセスid)/smapsは、カーネル内の該当プロセスのメモリ利用状況を表示するAPIです。それを使って実験したいと思います。&lt;br /&gt;
dashはDebian版軽量シェルでシステムのシェルスクリプトを実行するのに使われます。&lt;br /&gt;
さて、$$はシェル自身のプロセスidですので、/proc/$$/smapsとすると現在使っているシェルのメモリ利用状況がわかります。&lt;br /&gt;
注目するのは Shared_Clean と Private_Clean の値です。&lt;br /&gt;
Shared_Clean はシェアしているメモリです。&lt;br /&gt;
Private_Clean は自らのメモリです。&lt;br /&gt;
クリーンな、という意味は、まだそのページは変更されていない（書き込みがおこっていない）という意味です。&lt;br /&gt;
まず最初、dashを起動してdashシェル環境でメモリ利用状況をみます。&lt;br /&gt;
この時、引き継ぐものがないのでPrivate_Cleanが76kB (= Rssの値と同じ)、Shared_Cleanが0kBとなっています。&lt;br /&gt;
次にdashの中でさらにdashを起動します。つまり最初のdashが親プロセスとなった新しいdashです。&lt;br /&gt;
この上で両方の値をみるとPrivate_Cleanが0kB、Shared_Cleanが76kB(= Rssの値と同じ)となっています。&lt;br /&gt;
つまり、子プロセス側となったdashのメモリは、この時点ではシェアしているものを使っていることがわかります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ dash&lt;br /&gt;
 $ cat /proc/$$/smaps | head -9&lt;br /&gt;
 08048000-08060000 r-xp 00000000 08:01 4825       /bin/dash&lt;br /&gt;
 Size:                 96 kB&lt;br /&gt;
 Rss:                  76 kB&lt;br /&gt;
 Pss:                  76 kB&lt;br /&gt;
 Shared_Clean:          0 kB&lt;br /&gt;
 Shared_Dirty:          0 kB&lt;br /&gt;
 Private_Clean:        76 kB&lt;br /&gt;
 Private_Dirty:         0 kB&lt;br /&gt;
 Referenced:           76 kB&lt;br /&gt;
 $ dash&lt;br /&gt;
 $ cat /proc/$$/smaps | head -9&lt;br /&gt;
 08048000-08060000 r-xp 00000000 08:01 4825       /bin/dash&lt;br /&gt;
 Size:                 96 kB&lt;br /&gt;
 Rss:                  76 kB&lt;br /&gt;
 Pss:                  34 kB&lt;br /&gt;
 Shared_Clean:         76 kB&lt;br /&gt;
 Shared_Dirty:          0 kB&lt;br /&gt;
 Private_Clean:         0 kB&lt;br /&gt;
 Private_Dirty:         0 kB&lt;br /&gt;
 Referenced:           76 kB&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mmap ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mmap(2)はファイルをメモリのように使うためのシステムコールです。mmapを使うことによってファイルとメモリの境目はなくなります。次のプログラムを見てください。これはファイルをオープンした後、ファイルの中身を文字型配列としてアクセスしています。readを使って読み込みをしているわけではありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* プログラムmmap.c&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&#039;C&#039; line=&amp;quot;1&amp;quot; &amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
#include &amp;lt;fcntl.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/mman.h&amp;gt;&lt;br /&gt;
int main(void)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct stat st;&lt;br /&gt;
  char *p;&lt;br /&gt;
  int i;&lt;br /&gt;
  fd=open(&amp;quot;dat&amp;quot;,O_RDWR);&lt;br /&gt;
  fstat(fd, &amp;amp;st);&lt;br /&gt;
  p=mmap(0,st.st_size,(PROT_READ|PROT_WRITE),MAP_PRIVATE,fd,0);&lt;br /&gt;
  for(i=0; i &amp;lt; st.st_size; i++) {&lt;br /&gt;
    printf(&amp;quot;[%c]&amp;quot;,p[i]);&lt;br /&gt;
  }&lt;br /&gt;
  close(fd);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*  実行&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ echo -n &#039;abcdefg&#039; &amp;gt; dat&lt;br /&gt;
 $ cc mmap.c&lt;br /&gt;
 $ ./a.out&lt;br /&gt;
 [a][b][c][d][e][f][g]$ &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ファイルdatの中身は&amp;quot;abcdefg&amp;quot;となっています。datをオープンしfstatでファイルのステータス情報を取り出します。そのステータス情報の中のファイルサイズがst.st_sizeです。mmapを使って、ファイルdatの中身をメモリ空間として割り当てます。そのポインタがpです。ループ内でpの中身を表示させると、ファイルの内容と同じであることがわかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはメモリの中にファイルを読み込んでいるわけではありません。ファイルをメモリにマップしたのです。スワップページからページインするのと良く似ていると気が着く人もいるでしょうが、基本的には同じ動作で、ファイルを読み出す過程はページインと同じ仕組みです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これは今日のUNIX系オペレーティングシステムでの重要なメカニズムの一つです。たとえばLinuxではプログラムを実行する時、バイナリの実行ファイルや標準ライブラリを読み込む動作をするのではなくmmapでマップします。これでファイルシステムとは違う記憶領域であるはずのメモリ内に存在するのと、まったく同じ動作ができます。動作時に実行コードをページインします。&lt;br /&gt;
&lt;br /&gt;
glibcでのmalloc実装は/dev/zeroをオープンし一定領域をmmapで確保し、その領域から必要な分を切り出してプログラム側に返却しています。つまりmallocを呼び出したプログラムは/dev/zeroの領域を使っています。/dev/zeroは物理的なデバイスの実体を持たないので、カーネルが与えたメモリ空間になります。mmapはこんな使い方もされているという一例です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
さて、この例題プログラムではマップする属性をMAP_PRIVATEとしているので、ファイルの内容を読み込みはしますが、メモリ領域に書き込んでも、それはファイルには書き込まれません。これをMAP_SHAREDとするとファイルと同期を取ることができます。このファイルを複数のプログラムからオープンすると共有メモリとして利用できます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 内容をアップデートして同期するにはメモリに書き込み後、msync(2)やmunmap(2)を呼ぶことが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 単一レベル記憶 ===&lt;br /&gt;
&lt;br /&gt;
ファイルもメモリも、さらにデバイスすらも単純な1つの記憶空間として扱おうというコンセプトが単一レベル記憶です。&lt;br /&gt;
現在、オペレーティングシステムレベルでサポートしているのはIBM社のSystem iシリーズ&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
IBMのサイトにあるIBM System iの単一レベル記憶の解説 :  http://www-06.ibm.com/systems/jp/i/seminar/reconf/reconf1.shtml&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
ぐらいしかないので、&lt;br /&gt;
インターネット上で説明を探すとIBM System iの機能＝単一レベル記憶の定義みたいな説明しかありませんが、&lt;br /&gt;
実は、その歴史は古く1960年代に作られたMultics上に既に実装&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Multics and More VM&lt;br /&gt;
https://users.cs.duke.edu/~chase/cps210-archive/slides/multics-vm.pdf&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXは単一レベル記憶を前提としているデザインはありませんが、現在のUNIX系のオペレーティングシステムはmmapを実装することによってファイルもメモリも、そしてデバイスも同様に扱うことができる利益を得ています。&lt;br /&gt;
例としては今時のLinuxやその他UNIX系のオペレーティングシステムでは実行バイナリやライブラリを動かすとき、一々ファイルの中身を読み込む動作をせず、実行するバイナリデータを内部でマップしてしまいます。&lt;br /&gt;
ですから古典的なUNIXで言われるような、「実行バイナリファイルをメモリに読み込み実行する」という表現は、少なくとも現在のLinuxの実行時の表現としては適切ではないという状況になっています。あとデバイスの利用例としては、malloc()のいくつかの実装&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
The GNU Allocator&lt;br /&gt;
https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
では内部で記憶領域を確保するとき/dev/zeroをmmapでオープンして使っています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E7%92%B0%E5%A2%83%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1721</id>
		<title>システム環境を考えてみる</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E7%92%B0%E5%A2%83%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1721"/>
		<updated>2022-02-17T05:18:48Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 新たなユーザアカウントを加える場合 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===  環境を考えてみる ===&lt;br /&gt;
&lt;br /&gt;
[[image:Desktop_knoppix.png||thumb|360px|Knoppix Desktop]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もし&lt;br /&gt;
[http://www.ubuntu.com/ Ubuntu]、 &lt;br /&gt;
[https://getfedora.org/ Fedora]、 &lt;br /&gt;
[https://www.centos.org/ CentOS]、 &lt;br /&gt;
[https://www.debian.org/ Debian]&lt;br /&gt;
あるいは&lt;br /&gt;
[http://vinelinux.org/ Vine Linux]&lt;br /&gt;
のようなデスクトップ向けGNU/Linuxを使っているのでしたら、使い勝手はいわゆるパソコンと変わらないでしょう。Webブラウザ、ワードプロセッサ、プレゼンテーション、あるいはメールを出すにしてもWindows XPやMacOS Xの上で提供されているのと同じようなアプリケーションスイート(Application suite ) [http://www.openoffice.org/ OpenOffice] / [http://www.libreoffice.org/ LibreOffice] があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
「[[オペレーティングシステムとは何か]]」のページで説明した通り、カーネルと、その上にあるミドルウェア、そしてアプリケーションは独立した存在です。ミドルウェアにしてもアプリケーションにしてもソフトウェアは利用目的あるいは好みによって入れ換えることができます。たとえば多くのGNU/Linuxディストリビューションのデスクトップ環境を変更することができます。デスクトップ環境は、そのコンピュータの使い勝手と印象を決める重要なミドルウェアですが、それであっても&lt;br /&gt;
[https://www.gnome.org/ GNOME]、&lt;br /&gt;
[https://www.kde.org/ KDE]、&lt;br /&gt;
[http://www.xfce.org/ xfce]&lt;br /&gt;
などを好みで入れ替えることができる選択肢が用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
「UNIXはキャラクタユーザインタフェース(CUI)である」と思い込んでいる人も世の中にはたくさんいます。UNIXが生まれた1960年代には、そもそも今日のようなGUI(グラフィックユーザインタフェース)などなかったわけですから、むかしはCUI しかなかったというのは当然です。今日のUNIXはCUIでもGUIでもありません。なぜならばユーザレベルでCUIかGUIのどちらのインタフェースを選ぶかはユーザ次第だからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
過去においてはGUIとCUIの両方が用意されていてもCUIを選ぶユーザも多かったというのは事実です。なぜかというとGUIを使ってUNIXをきちんと走らせようとすると、高速で高価なハードウェアが必要だったからです。&lt;br /&gt;
別の言い方をすると、GUIのために計算機の資源を割くといったことよりも、そのための資源をたとえばコンパイルとか本来処理すべきものに使っていたといえるでしょう。&lt;br /&gt;
近年になりデスクトップパソコンレベルでもCPUの処理速度が劇的に速くなり、ハードディスクの容量も格段に大きくなり、大量のメモリを搭載するようになり、性能の高いグラフィックチップを使うのが一般になり、[https://www.youtube.com/watch?v=PerCs2r8WIA  GUIを使うのがあたりまえ]の時代になりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今やGNU/Linux環境は他のパソコンとかわらないグラフィカルなユーザインタフェース&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://www.compiz.org/ Compiz fusion] のように高性能グラフィックボードと前提としたOpenGLベースのGUIがもたらす視覚効果はさらにその先を進んでいます。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を提供しています。既にエンドユーザ市場のために、いわゆるパソコンと呼ばれるコンシューマー向けデスクトップ環境を持つPCハードウェアのセット&amp;lt;ref&amp;gt;国内では2008年10月にDELL Dell™ Inspiron™ Mini 9ベーシックパッケージ(Ubuntu対応)が販売されています。ASUS Eee PCの海外版は[Xandros http://xandros.com]が搭載されています。 &amp;lt;/ref&amp;gt;も存在しています。&lt;br /&gt;
今日においては、MacやWindowsと同じような使い勝手のパソコンとして販売されるレベルになっています。&lt;br /&gt;
&lt;br /&gt;
=== スマートフォンからスーパーコンピューターまで ===&lt;br /&gt;
&lt;br /&gt;
[[image:OSFamily2017Nov.png||thumb|300px|Top500のリストより (2017/11)]]&lt;br /&gt;
&lt;br /&gt;
[[image:IDC-Smartphone-OS-share.png||thumb|300px|IDCのスマートフォンOS市場占有率の資料 (2017/5)]]&lt;br /&gt;
&lt;br /&gt;
Linuxカーネルは、GoogleがスマートフォンOSとして作ったAndroid&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
What is Android? http://code.google.com/android/what-is-android.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://developer.apple.com/library/ios/#documentation/Miscellaneous/Conceptual/iPhoneOSTechOverview/IPhoneOSOverview/IPhoneOSOverview.html About iOS Development]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
から&lt;br /&gt;
IBM @server zSeries&lt;br /&gt;
&amp;lt;ref&amp;gt;Linux on z Systems empowers your developers  https://youtu.be/ZnP5OnpOxWI &amp;lt;/ref&amp;gt;&lt;br /&gt;
のようなメインフレームまで基本的には同じ構造のものが動いています。もちろん必要とされるミドルウェアやアプリケーション、カーネルのコンフィグレーションはスマートフォンとメインフレームでは異なってくるのは当然ですが、やはりどちらもLinuxと多くの[https://www.gnu.org/software/ GNUコマンドやライブラリ]から成り立っているのでGNU/Linuxと呼ばれるべきものです。またGNU/Linuxはたくさんのコンピュータをつないたクラスターコンピュータのシステムとしても使われています。&lt;br /&gt;
Androidはスマートフォンのプラットホームとして常に81~87パーセント(2016-2017)のシェアを占めています。さらにUNIXとして考えるならiOSもUNIXとして分類出来ますから、2017年第1四半期ではスマートフォン市場の99.8パーセントがUNIXということになります。&lt;br /&gt;
HPC分野(スーパーコンピュータ)では広く使われていたGNU/Linuxですが2017年11月期発表のTop500ではOperating System FamilyはLinuxのみになりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [http://www.ibm.com/developerworks/linux/linux390/ IBM メインフレーム] / [https://www-03.ibm.com/systems/z/os/linux/ Linux OS on IBM z Systems]&lt;br /&gt;
* [http://www.android.com/ Android]&lt;br /&gt;
** スマートフォン・マーケットにおける[http://www.idc.com/prodserv/smartphone-os-market-share.jsp Androidのシェア]（最新版）&lt;br /&gt;
* [http://www.top500.org/ 世界の HPC Top500]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
GNU/Linuxの「何でもできる」というのは醍醐味の一つでもあるのですが、しかし、何でもできるといってもGNU/Linuxが搭載されたスーパーコンピュータを手に入れた初心者がスーパーコンピュータの計算能力をフルに発揮するような操作が出来るわけではありません。&lt;br /&gt;
そしてまた、本当のGNU/Linuxの能力の全容を理解しようとすると、本質的にはスマートフォン からスーパーコンピュータまでのコンピューティングを知ることになります。&lt;br /&gt;
手に入ることと、使いこなせることとを混同してしまうあたりが&amp;quot;UNIX(GNU/Linux)は難しい&amp;quot;という部分につながっているのではないかと筆者は想像しています。&lt;br /&gt;
しかし最も大切なのはUNIX的な考え方（使うことではなく）を理解することではないでしょうか。&lt;br /&gt;
&lt;br /&gt;
=== GNU/Linuxの何を学ぶべきなのか === &lt;br /&gt;
&lt;br /&gt;
「GNU/Linuxでもワードプロセッサのアプリケーションが動きます」というレベルで満足であれば、この先を読み進める必要はありません。このテキストではGNU/LinuxをベースにしてUNIX的な考え方を学ぶというのがテーマです。残念ながらGNU/LinuxやUNIXのHOWTOではありません。アプリケーションレベルでのハウツー本が欲しいのであれば&lt;br /&gt;
[https://goo.gl/ik1LUf Amazonにたくさんの入門本が出ています]ので、自分にあった本を選んで、手元において読んだ方がいいでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかしコンピュータサイエンスの基本としてオペレーティングシステムを学ぶのであれば、我々は最初にUNIXが創造された時から脈脈と受け継がれるUNIX的なコンセプトを学ぶことが近道だと筆者は思います。最終的にそれが携帯電話に使われようが、メインフレームに使われようが、スーパーコンピュータで使われようが、学ぶための出発点は同じだからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これからこの先、何を学ぶべきかのポイントをざっくりと書き出してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ざっくりリストアップしてみる ====&lt;br /&gt;
&lt;br /&gt;
*  アクセス権限モデル&lt;br /&gt;
** 管理者であるrootと一般ユーザとの区別され一般ユーザは限られた範囲でしか権限を持たない&lt;br /&gt;
**   ユーザID(uid)やグループID(gid)の設定と利用について&lt;br /&gt;
&lt;br /&gt;
* 入出力の統一化&lt;br /&gt;
**   入出力は標準入出力とファイルに統一されている&lt;br /&gt;
**  ただしUNIXの長い歴史の中で不統一な所も出てきてはいる&lt;br /&gt;
&lt;br /&gt;
* / から始まる階層化されたファイルの名前空間&lt;br /&gt;
**  ディレクトリ中にファイルがあり、絶対パスや相対パスでファイルへアクセスしている&lt;br /&gt;
&lt;br /&gt;
* プロセスの構成&lt;br /&gt;
** 親プロセスから子プロセス生成され、実行環境が継承される&lt;br /&gt;
&lt;br /&gt;
*  プロセス間での通信&lt;br /&gt;
**  記憶空間の共有について&lt;br /&gt;
**  ファイルもメモリも同じようにアクセスする仕組み&lt;br /&gt;
**  TCP/IPネットワーク機能について&lt;br /&gt;
&lt;br /&gt;
*  最小の機能構成された豊富なツール&lt;br /&gt;
**  小さなツール群を組み合わせて柔軟に処理を行う&lt;br /&gt;
&lt;br /&gt;
* ワークベンチ&lt;br /&gt;
** 作業を行うために豊富なツール群を用意している&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
本書（本サイト）では、以降の章でこれらの内容を取り上げていきますが、まずはGNU/Linuを触ってみましょう。&lt;br /&gt;
&lt;br /&gt;
=== ログイン ===&lt;br /&gt;
[[image:Ubuntu_804_16.png||thumb|300px|Ubuntu 8.04 ログイン画面]]&lt;br /&gt;
通常、ユーザがGNU/Linuxを使うには、まずログインするところから始まります。アカウント名とパスワードを入力します。KNOPPIXなどは自動的にログインした状態から始まりますが、このような自動的にログインしているのは例外的です。通常はディストリビューションのインストールの設定の時にインストーラが最低ひとつはユーザアカウントの作成を尋ねてくるので、その指示に従い入力すると自動的に作成されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 新たなユーザアカウントを加える場合 ==== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初はインストール時に設定したユーザ名だけですが、&lt;br /&gt;
さらにユーザが必要な場合、 adduser コマンドや、あるいは GUI ツールを使って新しいユーザを加えることができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:Gnome-UserSetting.png|right|500px|Gnome ユーザ設定]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、ここでは基本中の基本である adduser コマンドを使う場合を説明しましょう。&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
KDE や Gnome 環境でも GUI を使ったツールは用意されていますが、ここではすべての環境に共通な基本的コマンドを使っての説明を行います。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
新しいユーザを加えるには root 権限を使う必要があります。ここではログインすることなく、 &#039;&#039;&#039;sudo&#039;&#039;&#039; を使いコマンドを root 権限で実行します。&lt;br /&gt;
adduser コマンドを使いユーザのアカウントを造り、パスワードを設定し、ホームディレクトリを作成します。アカウント下は hironobu というアカウントを作る例です。&lt;br /&gt;
adduserもsudoもPOSIX定義のコマンドではありませんが&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
POSIXで定義しているコマンドユーティリティは次のページで参照できます。&lt;br /&gt;
http://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;、&lt;br /&gt;
GNU/Linuxであればスーパーコンピュータであろうが、サーバであろうが、デスクトップであろうがこれらの基本コマンドは同じものが用意されています。&lt;br /&gt;
&lt;br /&gt;
いま作った hironobu というアカウントよりログインするとユーザ hironobu の権限でプログラムが動きます。ユーザの持っているユーザIDやグループID がユーザ権限であり、その権限の範囲でファイルなどへのアクセスなどが出来ます。唯一 root 権限だけが(原則)すべてのファイルにアクセスできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sudo adduser hironobu&lt;br /&gt;
 [sudo] password for foo:&lt;br /&gt;
 Adding user hironobu...&lt;br /&gt;
 Adding new group hironobu (1001).&lt;br /&gt;
 Adding new user hironobu (1001) with group hironobu.&lt;br /&gt;
 Creating home directory /home/hironobu.&lt;br /&gt;
 Copying files from /etc/skel&lt;br /&gt;
 Enter new UNIX password: &lt;br /&gt;
 Retype new UNIX password: &lt;br /&gt;
 passwd: password updated successfully&lt;br /&gt;
 Changing the user information for hironobu&lt;br /&gt;
 Enter the new value, or press return for the default&lt;br /&gt;
        Full Name []: Hironobu SUZUKI&lt;br /&gt;
        Room Number []: &lt;br /&gt;
        Work Phone []: &lt;br /&gt;
        Home Phone []: &lt;br /&gt;
        Other []: &lt;br /&gt;
 Is the information correct? [y/n] y&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== コマンドを動かす ===&lt;br /&gt;
&lt;br /&gt;
シェルでコマンドを動かす時は、端末上でシェルプロンプトが出ている状態でコマンドを入力します。ルートディレクトリ (ファイルシステムの始まりである&amp;quot;/&amp;quot; ディレクトリを特にルートディレクトリと呼びます ) にどんなファイルやディレクトリがあるかlsコマンドを使って見てみましょう。-Fオプションはファイルの種類&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
表示されている名前の後ろに/があればディレクトリ、@はシンボリックリンク、*は実行ファイル、なければ普通のファイルです。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を表示するオプションです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % ls -F /&lt;br /&gt;
  bin/   cdrom/  etc/     home/    lib/         mnt/  proc/  sbin/  usr/&lt;br /&gt;
  boot/  dev/    floppy/  initrd/  lost+found/  opt/  root/  tmp/   var/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
短く説明すると、この表示されている範囲では/bin、/sbin が、あと /usr/bin、/usr/sbin にコマンドが入っています。binは通常使うコマンド、sbin はシステム管理に使うコマンドが入っています。/var はログデータファイルや一時的に保管しているデータファイルを集めているディレクトリです。/dev はデバイスファイルが入っているディレクトリです。/proc は実際のファイルが入っているわけはなく、カーネルなどの情報をファイルの形で見せているインタフェースです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % pwd &lt;br /&gt;
  /home/hironobu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pwd は自分がどこのディレクトリにいるか表示するコマンドです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % mkdir desk&lt;br /&gt;
  % cd desk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mkdir はディレクトリを作るコマンドで、今&amp;quot;desk&amp;quot;という名前のディレクトリを作りました。cd は現在いるディレクトリであるカレントディレクトリを移動するコマンドです。もう一度pwdをしてみるとわかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % pwd &lt;br /&gt;
  /home/hironobu/desk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
自分の現在使っている環境より派生しているプロセスをpsコマンドを使って表示させてみましょう。今のシェルを含めて表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  $ ps&lt;br /&gt;
   PID TTY          TIME CMD&lt;br /&gt;
   516 pts/1    00:00:00 bash&lt;br /&gt;
   937 pts/1    00:00:00 ps&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PIDはプロセスID、TTYはターミナル名、TIMEは今までにプロセスが消費したCPU時間、CMDはコマンド名です。では、今、このコンピュータ上で動いているプロセスは全部でいくつあるでしょうか。-Aオプションを使うと、すべてのプロセスが表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps -A &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
端末を流れていった行まで戻って数えるのは大変そうです。1行に1プロセスが表示されているのでwcを使ってカウントすれば簡単に数えることができます。パイプ | を使いpsの出力をwcの入力にしてしまいます。行数だけ数えて表示させるにはwcの-lオプションを使います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  $ ps -A | wc -l&lt;br /&gt;
     46&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 自分自身のプロセスつまりps -Aのプロセスとwc -lのプロセスをカウントいることを注意してください。&lt;br /&gt;
&lt;br /&gt;
今度は、どんなプロセスがあるのか見てみます。画面を一定量スクロールさせるコマンドmoreを使います。moreで止まっている画面を先に進める時はスペースを入力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  $ ps -A | more &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一番最初に見出し行がついているのを忘れていました。先ほどのプロセス数は1つ多いことになります。それでは見出し行を出力しないにはどうしたら良いでしょうか? &lt;br /&gt;
オンラインマニュアルでpsを見てみるとオプション &amp;quot;h&amp;quot; を使うことがわかりました。&lt;br /&gt;
オプション &amp;quot;--no-headers&amp;quot; も同様に見出し行を出力しない時に使うこともわかりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps h -A | wc -l &lt;br /&gt;
   45&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このパイプで送るというのはUNIXが生み出したアイデアです。ps はプロセスを表示するという機能moreやwcは表示のみ、入力された文字数、単語数、行数を数えるのみの、いわば専門の機能を提供するツールです。psにプロセス数を数える機能や、画面で表示した時に画面のサイズに合わせて一旦停止するといった機能をくわえるという発想も可能でしょう。しかし、そうするとpsのプログラムサイズがどんどん大きくなっていきます。またmoreやwcの機能は別にpsに限らず、他のツールでも同様に必要になります。ならばmoreやwcを独立して作&lt;br /&gt;
り、他のツールでも組み合わせれるように共通化してしまえば、システム全体としてみた場合、さらにコンパクトになります。これがUNIX的な発想です。この背景はソフトウェア工学的な機能分割によるツールの再利用性向上と組合せによるソフトウェア生産性の向上という共通理解&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 &#039;&#039;ソフトウェア作法&#039;&#039; , Brian W.Kernighan (著), P.J.Plauger (著), 木村 泉 (翻訳), &lt;br /&gt;
 共立出版 (1981/05), &lt;br /&gt;
ISBN 4320021428&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
があります。&lt;br /&gt;
&lt;br /&gt;
=== ファイルを参照する === &lt;br /&gt;
&lt;br /&gt;
UNIXでは単純にファイルの中身を見てみるといっても、ツールが色々ある分、色々なアプローチがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cat /etc/passwd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
catの引数にファイル名を与えると、ファイルを読み込み標準出力へ出力するという動作をします。よってファイルの中身を表示することができます。先程使ったmoreを使っても良いでしょう。他にはどんな方法がありますか？入力が/etc/passwdファイル、出力が標準出力、そして内容を変更しないという条件がそろえばcatと同じことができるはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sed -e &#039;s/.*/&amp;amp;/&#039; /etc/passwd &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sedコマンドは文字列を与えたルールに従って置き換えを行うツールです。こ&lt;br /&gt;
こで与えた置き換えルールは「すべての文字パターンに一致することとし、そ&lt;br /&gt;
の一致したパターンを一致したパターンに置き換えよ」ということをしていま&lt;br /&gt;
す。ですから、/etc/passwdと同じ内容が出力されるはずです。本当でしょうか？この標準出力をファイルへセーブして、処理前、処理後の内容を比較て&lt;br /&gt;
みましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sed -e &#039;s/.*/&amp;amp;/&#039; /etc/passwd  &amp;gt; /tmp/i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
標準出力をファイルに格納するにはコマンドの後に&amp;quot;&amp;gt;&amp;quot;をつけます。この機能&lt;br /&gt;
のことをリダイレクションといいます。入力も同じように&amp;quot;&amp;lt;&amp;quot;を使うとファイ&lt;br /&gt;
ルが標準入力へリダイレクションされます。ファイルではなく&amp;quot;&amp;lt;&amp;quot;を使い標準&lt;br /&gt;
入力から読み込むようにすることもできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sed -e &#039;s/.*/&amp;amp;/&#039; &amp;lt; /etc/passwd  &amp;gt; /tmp/i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これで/tmp/iに出力がセーブされました。今度は差分を探してみます。それに&lt;br /&gt;
はdiffコマンドを使います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ diff /etc/passwd /tmp/i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
何も出力されません。UNIXは寡黙を良しとする文化なので、これは差分がないときは何も出力されないのです。&lt;br /&gt;
うまくいっているようです。あと diff の特徴として終了ステータスでも差分があったか否かがわかるようになっているコマンドです。&lt;br /&gt;
次のように実行すると、0 (変更なし）、1（差分あり）、2（異常終了した）が表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ diff foo bar &amp;gt; /dev/null ; echo $? &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:他にファイルの中身を表示させる方法には、どんな方法があるだろうか。少なくともあと2つは考えてみよう。&lt;br /&gt;
&lt;br /&gt;
=== グラフィカルなデスクトップ環境 ===&lt;br /&gt;
&lt;br /&gt;
GnomeやKDEといったグラフィカルなデスクトップ環境をGNU/Linuxは用意しています。&lt;br /&gt;
今やGNU/LinuxのGUI環境はMacOSやWindowsといった身近なパソコン環境にひけをとりません。&lt;br /&gt;
GNU/Linuxの用意している3Dグラフィック環境 compiz fusionなどは視覚的なギミック（あまり意味はないが、派手に見せて驚かせる）な機能を兼ね備えています。&lt;br /&gt;
意味があるかどうかは別としてGUI環境をカスタマイズしてMac OSのように見せることもやろうと思えばできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Customize Ubuntu 18.04 : how to fully customize GNOME 3 | Make Ubuntu 18.04 look like Mac Os&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;sfsKwzElxQg&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Linux Mint 17.1 Cinnamon Edition - A Quick Look&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;K6pmKJ_-nFQ&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Linux Mint 17.2 Rafaela Cinnamon Edition - See What&#039;s New&lt;br /&gt;
&amp;lt;youtube&amp;gt;BUrgsngJMVo&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIX系のウインドウシステムの主流はX Window System (以下Xと呼びます）です。Xは画面の描写のためのサーバと、&lt;br /&gt;
そこと通信を行うためのライブラリ群です。尚、GnomeやKDE やxfce4などは、その上に作られたユーザインタフェース環境を統一的に提供するフレーム&lt;br /&gt;
ワーク環境です。これらはシステム的に競合関係にあり、同時にどちらも使うことはできません。&lt;br /&gt;
&lt;br /&gt;
[[画像:Kde desktop.png|thumb|280px|KDEのスクリーンショット]]&lt;br /&gt;
[[画像:Ubuntu screen.jpg|thumb|280px|Gnome (ubuntu)のスクリーンショット]]&lt;br /&gt;
&lt;br /&gt;
1980年代UNIX上では、数多くのウインドウシステムが作られ、そして淘汰されていきました。&lt;br /&gt;
米SUN社は独自のウインドウシステムであるSunViewやNeWS を持っていましたし、日本で作られたGMW&amp;lt;ref&amp;gt;京都大学、オムロン、アステックが共同で開発&amp;lt;/ref&amp;gt;などもありました。&lt;br /&gt;
それらの中で今日まで生き残ったのがMITのProject Athenaで作られたX Window Systemです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Project Athenaはネットワーク経由でシステムを使うためのインフラと開発環境を提供するためのプロジェクトでした。&lt;br /&gt;
透過的ウィンドウシステムであるX Window Systemは、その中の１つのプロジェクトでした。&lt;br /&gt;
初期の頃は統一的かつ包括的なユーザ環境を提供するという能力はありませんでした。後にMotifやCDEといったフレームワーク（初期は Widget Toolkit と呼んでいた）が出現してきました。MotifやCDEは商用のソフトウェアです。ところが機能的にあまり発展することなく徐々に使われなくなっていきます。一時期はGUI環境がUNIXの弱点だともいわれていました。後に、オープンソースでGnomeやKDEが開発され、広がり、熟成されるに至ります。商用UNIXが提供するよりもはるかに完成度が高く、技術的も高度な、さらに、今風のGUI環境はオープンソースとして提供されて初めて発展することが出来たのです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xはその開発当初の目的から、ネットワーク透過的な、つまりネットワークで接続されているコンピュータを意識させないウインドウシステムを作ること&lt;br /&gt;
でした。ですから、一台のコンピュータ上で完結しているような単純なウインドウシステムよりプロトコルは複雑です。&lt;br /&gt;
またネットワーク透過を前提としているので、&lt;br /&gt;
ハードウェアコントロールとウィンドウシステムと独立している設計のため特別にハードウェアを意識するようなプロトコルではありません。&lt;br /&gt;
しかし今日においては、これらの課題はCPU/GPUの高速化、あるいはツール・ライブラリ類の充実化、実装技法の向上により他のウィンドウシステムと遜色のないものとなっています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|3]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E7%92%B0%E5%A2%83%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1720</id>
		<title>システム環境を考えてみる</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E7%92%B0%E5%A2%83%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B&amp;diff=1720"/>
		<updated>2022-02-17T05:11:30Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 脚注 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===  環境を考えてみる ===&lt;br /&gt;
&lt;br /&gt;
[[image:Desktop_knoppix.png||thumb|360px|Knoppix Desktop]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もし&lt;br /&gt;
[http://www.ubuntu.com/ Ubuntu]、 &lt;br /&gt;
[https://getfedora.org/ Fedora]、 &lt;br /&gt;
[https://www.centos.org/ CentOS]、 &lt;br /&gt;
[https://www.debian.org/ Debian]&lt;br /&gt;
あるいは&lt;br /&gt;
[http://vinelinux.org/ Vine Linux]&lt;br /&gt;
のようなデスクトップ向けGNU/Linuxを使っているのでしたら、使い勝手はいわゆるパソコンと変わらないでしょう。Webブラウザ、ワードプロセッサ、プレゼンテーション、あるいはメールを出すにしてもWindows XPやMacOS Xの上で提供されているのと同じようなアプリケーションスイート(Application suite ) [http://www.openoffice.org/ OpenOffice] / [http://www.libreoffice.org/ LibreOffice] があります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
「[[オペレーティングシステムとは何か]]」のページで説明した通り、カーネルと、その上にあるミドルウェア、そしてアプリケーションは独立した存在です。ミドルウェアにしてもアプリケーションにしてもソフトウェアは利用目的あるいは好みによって入れ換えることができます。たとえば多くのGNU/Linuxディストリビューションのデスクトップ環境を変更することができます。デスクトップ環境は、そのコンピュータの使い勝手と印象を決める重要なミドルウェアですが、それであっても&lt;br /&gt;
[https://www.gnome.org/ GNOME]、&lt;br /&gt;
[https://www.kde.org/ KDE]、&lt;br /&gt;
[http://www.xfce.org/ xfce]&lt;br /&gt;
などを好みで入れ替えることができる選択肢が用意されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
「UNIXはキャラクタユーザインタフェース(CUI)である」と思い込んでいる人も世の中にはたくさんいます。UNIXが生まれた1960年代には、そもそも今日のようなGUI(グラフィックユーザインタフェース)などなかったわけですから、むかしはCUI しかなかったというのは当然です。今日のUNIXはCUIでもGUIでもありません。なぜならばユーザレベルでCUIかGUIのどちらのインタフェースを選ぶかはユーザ次第だからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
過去においてはGUIとCUIの両方が用意されていてもCUIを選ぶユーザも多かったというのは事実です。なぜかというとGUIを使ってUNIXをきちんと走らせようとすると、高速で高価なハードウェアが必要だったからです。&lt;br /&gt;
別の言い方をすると、GUIのために計算機の資源を割くといったことよりも、そのための資源をたとえばコンパイルとか本来処理すべきものに使っていたといえるでしょう。&lt;br /&gt;
近年になりデスクトップパソコンレベルでもCPUの処理速度が劇的に速くなり、ハードディスクの容量も格段に大きくなり、大量のメモリを搭載するようになり、性能の高いグラフィックチップを使うのが一般になり、[https://www.youtube.com/watch?v=PerCs2r8WIA  GUIを使うのがあたりまえ]の時代になりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
今やGNU/Linux環境は他のパソコンとかわらないグラフィカルなユーザインタフェース&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://www.compiz.org/ Compiz fusion] のように高性能グラフィックボードと前提としたOpenGLベースのGUIがもたらす視覚効果はさらにその先を進んでいます。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を提供しています。既にエンドユーザ市場のために、いわゆるパソコンと呼ばれるコンシューマー向けデスクトップ環境を持つPCハードウェアのセット&amp;lt;ref&amp;gt;国内では2008年10月にDELL Dell™ Inspiron™ Mini 9ベーシックパッケージ(Ubuntu対応)が販売されています。ASUS Eee PCの海外版は[Xandros http://xandros.com]が搭載されています。 &amp;lt;/ref&amp;gt;も存在しています。&lt;br /&gt;
今日においては、MacやWindowsと同じような使い勝手のパソコンとして販売されるレベルになっています。&lt;br /&gt;
&lt;br /&gt;
=== スマートフォンからスーパーコンピューターまで ===&lt;br /&gt;
&lt;br /&gt;
[[image:OSFamily2017Nov.png||thumb|300px|Top500のリストより (2017/11)]]&lt;br /&gt;
&lt;br /&gt;
[[image:IDC-Smartphone-OS-share.png||thumb|300px|IDCのスマートフォンOS市場占有率の資料 (2017/5)]]&lt;br /&gt;
&lt;br /&gt;
Linuxカーネルは、GoogleがスマートフォンOSとして作ったAndroid&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
What is Android? http://code.google.com/android/what-is-android.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://developer.apple.com/library/ios/#documentation/Miscellaneous/Conceptual/iPhoneOSTechOverview/IPhoneOSOverview/IPhoneOSOverview.html About iOS Development]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
から&lt;br /&gt;
IBM @server zSeries&lt;br /&gt;
&amp;lt;ref&amp;gt;Linux on z Systems empowers your developers  https://youtu.be/ZnP5OnpOxWI &amp;lt;/ref&amp;gt;&lt;br /&gt;
のようなメインフレームまで基本的には同じ構造のものが動いています。もちろん必要とされるミドルウェアやアプリケーション、カーネルのコンフィグレーションはスマートフォンとメインフレームでは異なってくるのは当然ですが、やはりどちらもLinuxと多くの[https://www.gnu.org/software/ GNUコマンドやライブラリ]から成り立っているのでGNU/Linuxと呼ばれるべきものです。またGNU/Linuxはたくさんのコンピュータをつないたクラスターコンピュータのシステムとしても使われています。&lt;br /&gt;
Androidはスマートフォンのプラットホームとして常に81~87パーセント(2016-2017)のシェアを占めています。さらにUNIXとして考えるならiOSもUNIXとして分類出来ますから、2017年第1四半期ではスマートフォン市場の99.8パーセントがUNIXということになります。&lt;br /&gt;
HPC分野(スーパーコンピュータ)では広く使われていたGNU/Linuxですが2017年11月期発表のTop500ではOperating System FamilyはLinuxのみになりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [http://www.ibm.com/developerworks/linux/linux390/ IBM メインフレーム] / [https://www-03.ibm.com/systems/z/os/linux/ Linux OS on IBM z Systems]&lt;br /&gt;
* [http://www.android.com/ Android]&lt;br /&gt;
** スマートフォン・マーケットにおける[http://www.idc.com/prodserv/smartphone-os-market-share.jsp Androidのシェア]（最新版）&lt;br /&gt;
* [http://www.top500.org/ 世界の HPC Top500]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
GNU/Linuxの「何でもできる」というのは醍醐味の一つでもあるのですが、しかし、何でもできるといってもGNU/Linuxが搭載されたスーパーコンピュータを手に入れた初心者がスーパーコンピュータの計算能力をフルに発揮するような操作が出来るわけではありません。&lt;br /&gt;
そしてまた、本当のGNU/Linuxの能力の全容を理解しようとすると、本質的にはスマートフォン からスーパーコンピュータまでのコンピューティングを知ることになります。&lt;br /&gt;
手に入ることと、使いこなせることとを混同してしまうあたりが&amp;quot;UNIX(GNU/Linux)は難しい&amp;quot;という部分につながっているのではないかと筆者は想像しています。&lt;br /&gt;
しかし最も大切なのはUNIX的な考え方（使うことではなく）を理解することではないでしょうか。&lt;br /&gt;
&lt;br /&gt;
=== GNU/Linuxの何を学ぶべきなのか === &lt;br /&gt;
&lt;br /&gt;
「GNU/Linuxでもワードプロセッサのアプリケーションが動きます」というレベルで満足であれば、この先を読み進める必要はありません。このテキストではGNU/LinuxをベースにしてUNIX的な考え方を学ぶというのがテーマです。残念ながらGNU/LinuxやUNIXのHOWTOではありません。アプリケーションレベルでのハウツー本が欲しいのであれば&lt;br /&gt;
[https://goo.gl/ik1LUf Amazonにたくさんの入門本が出ています]ので、自分にあった本を選んで、手元において読んだ方がいいでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかしコンピュータサイエンスの基本としてオペレーティングシステムを学ぶのであれば、我々は最初にUNIXが創造された時から脈脈と受け継がれるUNIX的なコンセプトを学ぶことが近道だと筆者は思います。最終的にそれが携帯電話に使われようが、メインフレームに使われようが、スーパーコンピュータで使われようが、学ぶための出発点は同じだからです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これからこの先、何を学ぶべきかのポイントをざっくりと書き出してみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ざっくりリストアップしてみる ====&lt;br /&gt;
&lt;br /&gt;
*  アクセス権限モデル&lt;br /&gt;
** 管理者であるrootと一般ユーザとの区別され一般ユーザは限られた範囲でしか権限を持たない&lt;br /&gt;
**   ユーザID(uid)やグループID(gid)の設定と利用について&lt;br /&gt;
&lt;br /&gt;
* 入出力の統一化&lt;br /&gt;
**   入出力は標準入出力とファイルに統一されている&lt;br /&gt;
**  ただしUNIXの長い歴史の中で不統一な所も出てきてはいる&lt;br /&gt;
&lt;br /&gt;
* / から始まる階層化されたファイルの名前空間&lt;br /&gt;
**  ディレクトリ中にファイルがあり、絶対パスや相対パスでファイルへアクセスしている&lt;br /&gt;
&lt;br /&gt;
* プロセスの構成&lt;br /&gt;
** 親プロセスから子プロセス生成され、実行環境が継承される&lt;br /&gt;
&lt;br /&gt;
*  プロセス間での通信&lt;br /&gt;
**  記憶空間の共有について&lt;br /&gt;
**  ファイルもメモリも同じようにアクセスする仕組み&lt;br /&gt;
**  TCP/IPネットワーク機能について&lt;br /&gt;
&lt;br /&gt;
*  最小の機能構成された豊富なツール&lt;br /&gt;
**  小さなツール群を組み合わせて柔軟に処理を行う&lt;br /&gt;
&lt;br /&gt;
* ワークベンチ&lt;br /&gt;
** 作業を行うために豊富なツール群を用意している&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
本書（本サイト）では、以降の章でこれらの内容を取り上げていきますが、まずはGNU/Linuを触ってみましょう。&lt;br /&gt;
&lt;br /&gt;
=== ログイン ===&lt;br /&gt;
[[image:Ubuntu_804_16.png||thumb|300px|Ubuntu 8.04 ログイン画面]]&lt;br /&gt;
通常、ユーザがGNU/Linuxを使うには、まずログインするところから始まります。アカウント名とパスワードを入力します。KNOPPIXなどは自動的にログインした状態から始まりますが、このような自動的にログインしているのは例外的です。通常はディストリビューションのインストールの設定の時にインストーラが最低ひとつはユーザアカウントの作成を尋ねてくるので、その指示に従い入力すると自動的に作成されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 新たなユーザアカウントを加える場合 ==== &lt;br /&gt;
[[image:Gnome-UserSetting.png||thumb|300px|Gnome ユーザ設定]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最初はインストール時に設定したユーザ名だけですが、&lt;br /&gt;
さらにユーザが必要な場合、 adduser コマンドや、あるいは GUI ツールを使って新しいユーザを加えることができます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、ここでは基本中の基本である adduser コマンドを使う場合を説明しましょう。&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
KDE や Gnome 環境でも GUI を使ったツールは用意されていますが、ここではすべての環境に共通な基本的コマンドを使っての説明を行います。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
新しいユーザを加えるには root 権限を使う必要があります。ここではログインすることなく、 &#039;&#039;&#039;sudo&#039;&#039;&#039; を使いコマンドを root 権限で実行します。&lt;br /&gt;
adduser コマンドを使いユーザのアカウントを造り、パスワードを設定し、ホームディレクトリを作成します。アカウント下は hironobu というアカウントを作る例です。&lt;br /&gt;
adduserもsudoもPOSIX定義のコマンドではありませんが&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
POSIXで定義しているコマンドユーティリティは次のページで参照できます。&lt;br /&gt;
http://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html&lt;br /&gt;
&amp;lt;/ref&amp;gt;、&lt;br /&gt;
GNU/Linuxであればスーパーコンピュータであろうが、サーバであろうが、デスクトップであろうがこれらの基本コマンドは同じものが用意されています。&lt;br /&gt;
&lt;br /&gt;
いま作った hironobu というアカウントよりログインするとユーザ hironobu の権限でプログラムが動きます。ユーザの持っているユーザIDやグループID がユーザ権限であり、その権限の範囲でファイルなどへのアクセスなどが出来ます。唯一 root 権限だけが(原則)すべてのファイルにアクセスできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sudo adduser hironobu&lt;br /&gt;
 [sudo] password for foo:&lt;br /&gt;
 Adding user hironobu...&lt;br /&gt;
 Adding new group hironobu (1001).&lt;br /&gt;
 Adding new user hironobu (1001) with group hironobu.&lt;br /&gt;
 Creating home directory /home/hironobu.&lt;br /&gt;
 Copying files from /etc/skel&lt;br /&gt;
 Enter new UNIX password: &lt;br /&gt;
 Retype new UNIX password: &lt;br /&gt;
 passwd: password updated successfully&lt;br /&gt;
 Changing the user information for hironobu&lt;br /&gt;
 Enter the new value, or press return for the default&lt;br /&gt;
        Full Name []: Hironobu SUZUKI&lt;br /&gt;
        Room Number []: &lt;br /&gt;
        Work Phone []: &lt;br /&gt;
        Home Phone []: &lt;br /&gt;
        Other []: &lt;br /&gt;
 Is the information correct? [y/n] y&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== コマンドを動かす ===&lt;br /&gt;
&lt;br /&gt;
シェルでコマンドを動かす時は、端末上でシェルプロンプトが出ている状態でコマンドを入力します。ルートディレクトリ (ファイルシステムの始まりである&amp;quot;/&amp;quot; ディレクトリを特にルートディレクトリと呼びます ) にどんなファイルやディレクトリがあるかlsコマンドを使って見てみましょう。-Fオプションはファイルの種類&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
表示されている名前の後ろに/があればディレクトリ、@はシンボリックリンク、*は実行ファイル、なければ普通のファイルです。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を表示するオプションです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % ls -F /&lt;br /&gt;
  bin/   cdrom/  etc/     home/    lib/         mnt/  proc/  sbin/  usr/&lt;br /&gt;
  boot/  dev/    floppy/  initrd/  lost+found/  opt/  root/  tmp/   var/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
短く説明すると、この表示されている範囲では/bin、/sbin が、あと /usr/bin、/usr/sbin にコマンドが入っています。binは通常使うコマンド、sbin はシステム管理に使うコマンドが入っています。/var はログデータファイルや一時的に保管しているデータファイルを集めているディレクトリです。/dev はデバイスファイルが入っているディレクトリです。/proc は実際のファイルが入っているわけはなく、カーネルなどの情報をファイルの形で見せているインタフェースです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % pwd &lt;br /&gt;
  /home/hironobu&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
pwd は自分がどこのディレクトリにいるか表示するコマンドです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % mkdir desk&lt;br /&gt;
  % cd desk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mkdir はディレクトリを作るコマンドで、今&amp;quot;desk&amp;quot;という名前のディレクトリを作りました。cd は現在いるディレクトリであるカレントディレクトリを移動するコマンドです。もう一度pwdをしてみるとわかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  % pwd &lt;br /&gt;
  /home/hironobu/desk&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
自分の現在使っている環境より派生しているプロセスをpsコマンドを使って表示させてみましょう。今のシェルを含めて表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  $ ps&lt;br /&gt;
   PID TTY          TIME CMD&lt;br /&gt;
   516 pts/1    00:00:00 bash&lt;br /&gt;
   937 pts/1    00:00:00 ps&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PIDはプロセスID、TTYはターミナル名、TIMEは今までにプロセスが消費したCPU時間、CMDはコマンド名です。では、今、このコンピュータ上で動いているプロセスは全部でいくつあるでしょうか。-Aオプションを使うと、すべてのプロセスが表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps -A &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
端末を流れていった行まで戻って数えるのは大変そうです。1行に1プロセスが表示されているのでwcを使ってカウントすれば簡単に数えることができます。パイプ | を使いpsの出力をwcの入力にしてしまいます。行数だけ数えて表示させるにはwcの-lオプションを使います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  $ ps -A | wc -l&lt;br /&gt;
     46&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 自分自身のプロセスつまりps -Aのプロセスとwc -lのプロセスをカウントいることを注意してください。&lt;br /&gt;
&lt;br /&gt;
今度は、どんなプロセスがあるのか見てみます。画面を一定量スクロールさせるコマンドmoreを使います。moreで止まっている画面を先に進める時はスペースを入力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
  $ ps -A | more &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一番最初に見出し行がついているのを忘れていました。先ほどのプロセス数は1つ多いことになります。それでは見出し行を出力しないにはどうしたら良いでしょうか? &lt;br /&gt;
オンラインマニュアルでpsを見てみるとオプション &amp;quot;h&amp;quot; を使うことがわかりました。&lt;br /&gt;
オプション &amp;quot;--no-headers&amp;quot; も同様に見出し行を出力しない時に使うこともわかりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ ps h -A | wc -l &lt;br /&gt;
   45&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このパイプで送るというのはUNIXが生み出したアイデアです。ps はプロセスを表示するという機能moreやwcは表示のみ、入力された文字数、単語数、行数を数えるのみの、いわば専門の機能を提供するツールです。psにプロセス数を数える機能や、画面で表示した時に画面のサイズに合わせて一旦停止するといった機能をくわえるという発想も可能でしょう。しかし、そうするとpsのプログラムサイズがどんどん大きくなっていきます。またmoreやwcの機能は別にpsに限らず、他のツールでも同様に必要になります。ならばmoreやwcを独立して作&lt;br /&gt;
り、他のツールでも組み合わせれるように共通化してしまえば、システム全体としてみた場合、さらにコンパクトになります。これがUNIX的な発想です。この背景はソフトウェア工学的な機能分割によるツールの再利用性向上と組合せによるソフトウェア生産性の向上という共通理解&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 &#039;&#039;ソフトウェア作法&#039;&#039; , Brian W.Kernighan (著), P.J.Plauger (著), 木村 泉 (翻訳), &lt;br /&gt;
 共立出版 (1981/05), &lt;br /&gt;
ISBN 4320021428&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
があります。&lt;br /&gt;
&lt;br /&gt;
=== ファイルを参照する === &lt;br /&gt;
&lt;br /&gt;
UNIXでは単純にファイルの中身を見てみるといっても、ツールが色々ある分、色々なアプローチがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ cat /etc/passwd&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
catの引数にファイル名を与えると、ファイルを読み込み標準出力へ出力するという動作をします。よってファイルの中身を表示することができます。先程使ったmoreを使っても良いでしょう。他にはどんな方法がありますか？入力が/etc/passwdファイル、出力が標準出力、そして内容を変更しないという条件がそろえばcatと同じことができるはずです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sed -e &#039;s/.*/&amp;amp;/&#039; /etc/passwd &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sedコマンドは文字列を与えたルールに従って置き換えを行うツールです。こ&lt;br /&gt;
こで与えた置き換えルールは「すべての文字パターンに一致することとし、そ&lt;br /&gt;
の一致したパターンを一致したパターンに置き換えよ」ということをしていま&lt;br /&gt;
す。ですから、/etc/passwdと同じ内容が出力されるはずです。本当でしょうか？この標準出力をファイルへセーブして、処理前、処理後の内容を比較て&lt;br /&gt;
みましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sed -e &#039;s/.*/&amp;amp;/&#039; /etc/passwd  &amp;gt; /tmp/i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
標準出力をファイルに格納するにはコマンドの後に&amp;quot;&amp;gt;&amp;quot;をつけます。この機能&lt;br /&gt;
のことをリダイレクションといいます。入力も同じように&amp;quot;&amp;lt;&amp;quot;を使うとファイ&lt;br /&gt;
ルが標準入力へリダイレクションされます。ファイルではなく&amp;quot;&amp;lt;&amp;quot;を使い標準&lt;br /&gt;
入力から読み込むようにすることもできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ sed -e &#039;s/.*/&amp;amp;/&#039; &amp;lt; /etc/passwd  &amp;gt; /tmp/i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これで/tmp/iに出力がセーブされました。今度は差分を探してみます。それに&lt;br /&gt;
はdiffコマンドを使います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ diff /etc/passwd /tmp/i&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
何も出力されません。UNIXは寡黙を良しとする文化なので、これは差分がないときは何も出力されないのです。&lt;br /&gt;
うまくいっているようです。あと diff の特徴として終了ステータスでも差分があったか否かがわかるようになっているコマンドです。&lt;br /&gt;
次のように実行すると、0 (変更なし）、1（差分あり）、2（異常終了した）が表示されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 $ diff foo bar &amp;gt; /dev/null ; echo $? &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;調べてみよう&lt;br /&gt;
:他にファイルの中身を表示させる方法には、どんな方法があるだろうか。少なくともあと2つは考えてみよう。&lt;br /&gt;
&lt;br /&gt;
=== グラフィカルなデスクトップ環境 ===&lt;br /&gt;
&lt;br /&gt;
GnomeやKDEといったグラフィカルなデスクトップ環境をGNU/Linuxは用意しています。&lt;br /&gt;
今やGNU/LinuxのGUI環境はMacOSやWindowsといった身近なパソコン環境にひけをとりません。&lt;br /&gt;
GNU/Linuxの用意している3Dグラフィック環境 compiz fusionなどは視覚的なギミック（あまり意味はないが、派手に見せて驚かせる）な機能を兼ね備えています。&lt;br /&gt;
意味があるかどうかは別としてGUI環境をカスタマイズしてMac OSのように見せることもやろうと思えばできます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Customize Ubuntu 18.04 : how to fully customize GNOME 3 | Make Ubuntu 18.04 look like Mac Os&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;sfsKwzElxQg&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Linux Mint 17.1 Cinnamon Edition - A Quick Look&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;K6pmKJ_-nFQ&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Linux Mint 17.2 Rafaela Cinnamon Edition - See What&#039;s New&lt;br /&gt;
&amp;lt;youtube&amp;gt;BUrgsngJMVo&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIX系のウインドウシステムの主流はX Window System (以下Xと呼びます）です。Xは画面の描写のためのサーバと、&lt;br /&gt;
そこと通信を行うためのライブラリ群です。尚、GnomeやKDE やxfce4などは、その上に作られたユーザインタフェース環境を統一的に提供するフレーム&lt;br /&gt;
ワーク環境です。これらはシステム的に競合関係にあり、同時にどちらも使うことはできません。&lt;br /&gt;
&lt;br /&gt;
[[画像:Kde desktop.png|thumb|280px|KDEのスクリーンショット]]&lt;br /&gt;
[[画像:Ubuntu screen.jpg|thumb|280px|Gnome (ubuntu)のスクリーンショット]]&lt;br /&gt;
&lt;br /&gt;
1980年代UNIX上では、数多くのウインドウシステムが作られ、そして淘汰されていきました。&lt;br /&gt;
米SUN社は独自のウインドウシステムであるSunViewやNeWS を持っていましたし、日本で作られたGMW&amp;lt;ref&amp;gt;京都大学、オムロン、アステックが共同で開発&amp;lt;/ref&amp;gt;などもありました。&lt;br /&gt;
それらの中で今日まで生き残ったのがMITのProject Athenaで作られたX Window Systemです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Project Athenaはネットワーク経由でシステムを使うためのインフラと開発環境を提供するためのプロジェクトでした。&lt;br /&gt;
透過的ウィンドウシステムであるX Window Systemは、その中の１つのプロジェクトでした。&lt;br /&gt;
初期の頃は統一的かつ包括的なユーザ環境を提供するという能力はありませんでした。後にMotifやCDEといったフレームワーク（初期は Widget Toolkit と呼んでいた）が出現してきました。MotifやCDEは商用のソフトウェアです。ところが機能的にあまり発展することなく徐々に使われなくなっていきます。一時期はGUI環境がUNIXの弱点だともいわれていました。後に、オープンソースでGnomeやKDEが開発され、広がり、熟成されるに至ります。商用UNIXが提供するよりもはるかに完成度が高く、技術的も高度な、さらに、今風のGUI環境はオープンソースとして提供されて初めて発展することが出来たのです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Xはその開発当初の目的から、ネットワーク透過的な、つまりネットワークで接続されているコンピュータを意識させないウインドウシステムを作ること&lt;br /&gt;
でした。ですから、一台のコンピュータ上で完結しているような単純なウインドウシステムよりプロトコルは複雑です。&lt;br /&gt;
またネットワーク透過を前提としているので、&lt;br /&gt;
ハードウェアコントロールとウィンドウシステムと独立している設計のため特別にハードウェアを意識するようなプロトコルではありません。&lt;br /&gt;
しかし今日においては、これらの課題はCPU/GPUの高速化、あるいはツール・ライブラリ類の充実化、実装技法の向上により他のウィンドウシステムと遜色のないものとなっています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|3]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=Ubuntu_Live_CD&amp;diff=1719</id>
		<title>Ubuntu Live CD</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=Ubuntu_Live_CD&amp;diff=1719"/>
		<updated>2022-02-17T05:11:04Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* Ubuntu Live CD を使ってみよう */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;実際にLinuxを使ってみよう&lt;br /&gt;
&lt;br /&gt;
== Ubuntu Live CD を使ってみよう ==&lt;br /&gt;
&lt;br /&gt;
Ubuntu インストール用CD-ROMメディアを差し込んでブートし、メニューからLive CD利用を選択すると、そのままUbuntuが立ち上がります。画面はUbuntu 8.04 日本語バージョンのものです。&lt;br /&gt;
&lt;br /&gt;
* ブート時のメニュー&lt;br /&gt;
[[画像:Ubuntu_804_0.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Ubuntuブート終了後&lt;br /&gt;
[[画像:Ubuntu 804 1.png ]]&lt;br /&gt;
&lt;br /&gt;
（作成中）&lt;br /&gt;
----&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|2]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=Ubuntu%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%96%B9%E6%B3%95&amp;diff=1718</id>
		<title>Ubuntuインストール方法</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=Ubuntu%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%96%B9%E6%B3%95&amp;diff=1718"/>
		<updated>2022-02-17T05:09:51Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 脚注 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Ubuntu専用のマシンを作成する　==&lt;br /&gt;
&lt;br /&gt;
(注意） この内容は2008年に書かれたものなので過去の参考程度にしてください。&lt;br /&gt;
&lt;br /&gt;
:追記: VirtualBoxなどのバーチャルマシン環境で作る際も基本的に同じ要領です。&lt;br /&gt;
&lt;br /&gt;
ここでは既にハードディスクにインストールしてあるシステムを破棄する前提で（あるいは、まだ何も書き込まれていないハードディスクを使う前提で）、デスクトップ用Ubuntu専用のマシンとして使う環境をインストールする手順を説明しています。これはインストール方法を説明することを目的とはしておらず、インストールする際にどのような流れで作業を行うのか事前に把握することを目的としています。インストール方法は同じディストリビューションでもバージョンによって違いますし、もちろんディストリビューション間でも違います。しかし全体の作業の流れは同じようなものなので、まずインストールする前に一通り目を通しておくと良いでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
またここでは　日本語ローカライズドDesktop CD&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://www.ubuntulinux.jp/products/GetUbuntu 日本語ローカライズドDesktop CD]の入手方法&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
を既に入手しており、またインストールするコンピュータはネットワークに接続しインターネット上のサイトにアクセスできる環境であることとします。尚、ここで紹介しているインストール手順ではIPアドレスはDHCPで自動的に割り当てられるものになります。&lt;br /&gt;
&lt;br /&gt;
== インストール手順 ==&lt;br /&gt;
&lt;br /&gt;
ここではUbuntu 8.04 LTSでのインストールを行っています。&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール:Step_1]]&lt;br /&gt;
** まずブートから環境設定までの説明です。ここではインストールCDROMを入れてブートしてからキーボードの設定までのプロセスを説明します。&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール:Step_2]]&lt;br /&gt;
** ハードディスクのセットアップ〜ROOT/ユーザアカウント設定&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール:Step_3]]&lt;br /&gt;
** インストール開始〜リブート&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール:Step_4]]&lt;br /&gt;
** インストール後のシステムにログイン&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール:Step_5]]&lt;br /&gt;
** システムの更新開始〜更新中&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール:Step_6]]&lt;br /&gt;
** システムの更新中〜更新終了&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール:Step_7]]&lt;br /&gt;
** リブート (インストール終了）&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|2]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E5%AE%9F%E9%9A%9B%E3%81%ABGNU/Linux%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86&amp;diff=1717</id>
		<title>実際にGNU/Linuxを使ってみよう</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E5%AE%9F%E9%9A%9B%E3%81%ABGNU/Linux%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86&amp;diff=1717"/>
		<updated>2022-02-17T05:09:21Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 脚注 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===  実際にGNU/Linuxを使ってみよう ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではGNU/Linux&amp;lt;ref&amp;gt; GNU/Linuxのニュースサイト http://lwn.net/ &amp;lt;/ref&amp;gt;を用意し、実際に簡単な操作を行って正しく動いているかを確認までを行います。いずれにしろ何かのGNU/Linuxのディストリビューションを手元に用意して自分で触ってみない限りは実感が持てないので、まずは手を動かしてください。ここでは2つの方法を考えてみたいと思います。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
第1番目の方法はLive CDを使うというものです。Live CDにはGNU/Linux(のディストリビューション)が入っており、このCD-ROMを使って起動する(ハードディスクにはインストールしない)すると利用できるようになります。起動時にしろ、コマンドを起動する時にしろ、一度はCD-ROMからファイルを読み込むので、ハードディスクから読み込むよりは遅いですが、簡便さという点では優れているでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
第2番目の方法は[https://www.virtualbox.org/ VirtualBox]のような仮想マシンのソフトウェアをインストール&amp;lt;ref&amp;gt;Windows、OS X、Linux、Solarisで動きます。こちらのサイトを参考にしてください。 http://www.oracle.com/technetwork/jp/server-storage/virtualbox/overview/index.html&amp;lt;/ref&amp;gt;し、そのバーチャルマシン環境上でインストールすることです。十分なメモリ、ハーディディスク容量、高速なCPUなどのハードウェアの資源の制約等がない場合、こちらの方が使い勝手が良いでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここではGNU/Linuxを本格的にインストールするというよりも、まずはLinuxを手元のPCハードウェアで動かすことを目標としています。Linuxを動かし、オペレーティングシステムとしてどのような構造になっているかを学習するには、まず、このレベルから始めていきましょう。&lt;br /&gt;
&lt;br /&gt;
=== GNU/Linuxディストリビューション === &lt;br /&gt;
&lt;br /&gt;
狭義のオペレーティングシステムとはカーネルですが、広義のオペレーティングシステムは、カーネルと関連するシステムソフトウェア、および必要なコマンド群から出来ています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
GNU/Linuxの場合、単なるLinuxと呼ぶ場合カーネルを指します。広義のオペレーティングシステムは、ディストリビューション(直訳すると配布)というパッケージ化された形で存在しています。同じカーネルでも、それ以外のソフトウェアの組み合わせを変えるだけで、色々なバリエーションが出来るという良い例です。広義のシステムとして指す場合はGNU/Linuxと呼ぶと狭義の意味のLinuxと区別できて良いといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足:  本テキスト中では厳密にカーネルのLinuxとシステムのGNU/Linuxを呼びわけているわけではありませんが、特にシステム全体を意識したいときはGNU/Linuxと書いています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
世の中にディストリビューションがどれだけ存在しているか筆者にはわかりませんが、一般に認知されているディストリビューションは、[http://distrowatch.com/dwres.php?resource=popularity The DistroWatch Page]から検索することが可能です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot; class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float:right; margin-left: 10px;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.redhat.com/ Red Hat]&lt;br /&gt;
| [https://getfedora.org/ Fedora]&lt;br /&gt;
| [http://linuxmint.com/ Mint]&lt;br /&gt;
| [http://www.centos.org/ CentOS]&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.debian.org/ Debian]&lt;br /&gt;
| [http://www.gentoo.org/ GentooLinux]&lt;br /&gt;
| [http://www.opensuse.org/ openSUSE]&lt;br /&gt;
| [http://www.mageia.org/ Mageia] &lt;br /&gt;
|-&lt;br /&gt;
| [http://www.archlinux.org/ Arch Linux]&lt;br /&gt;
| [http://www.ubuntu.com/ Ubuntu]&lt;br /&gt;
| [http://www.knoppix.org/ KNOPPIX]&lt;br /&gt;
| [http://vinelinux.org/ Vine]&lt;br /&gt;
|}&lt;br /&gt;
日本が使えてメジャーなディストリビューションということで思い浮かぶのは、次のようなものです。同じディストリビューションでも、商用パッケージ販売版、自由にコピーして良いコミュニティ版など色々なバリエーションを含んでいます。&lt;br /&gt;
それぞれ特徴がありますし、使い勝手の良さは甲乙つけがたいですが、&lt;br /&gt;
筆者は普段ノートパソコンとデスクトップには&lt;br /&gt;
[http://www.debian.org Debian GNU/Linux]&lt;br /&gt;
か&lt;br /&gt;
[http://www.ubuntulinux.org/ ubuntu]&lt;br /&gt;
、&lt;br /&gt;
サーバーには [https://www.centos.org/ CentOS]&lt;br /&gt;
を使っています。&lt;br /&gt;
&lt;br /&gt;
Debian GNU/LinuxはGPLのライセンスの下で世界中のDebianデベロッパーが協力して作っているディストリビューションです。Debian GNU/Linuxという意味は、&lt;br /&gt;
「DebianはGNUソフトウェア群とLinuxカーネルから成り立っている」ということを示しています。&lt;br /&gt;
DebianにはカーネルがLinuxだけではなく他のカーネルを使っているものもあります。たとえば&lt;br /&gt;
[http://www.debian.org/ports/kfreebsd-gnu Debian GNU/kFreeBSD]&lt;br /&gt;
はFreeBSDカーネルを使ったDebianのディストリビューションです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばRed HatやCentOS、Fedoraはルーツは同じですがRed Hat(Red Hat Enterprise Linux)は企業サーバ向けディストリビューション、Fedoraはディスクトップ向け、CentOSはサーバ向けといったように方向性による分岐があり、Red Hat、Fedora、CentOS、各々のディストリビューションはどれもが活発に開発されています。このように色々なディストリビューションが存在するのがGNU/Linuxの特徴です。&lt;br /&gt;
&lt;br /&gt;
=== LiveCD ===&lt;br /&gt;
&lt;br /&gt;
これも色々なディストリビューションがあります。先程distrowatch.comで調べて数えたら300種類以上(2019年3月時点) &amp;lt;ref&amp;gt;2006年当時は90種類強のリストでした。&amp;lt;/ref&amp;gt;ありました。&amp;lt;del&amp;gt;「&#039;&#039;[[KNOPPIXを使ってみよう]]&#039;&#039;」のページではFREEDUCとKNOPPIXの2つを紹介しています。&amp;lt;/del&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;del&amp;gt;[[KNOPPIXを使ってみよう]]&amp;lt;/del&amp;gt; このテキストは obsoleted です。&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntu_Live_CD]]を使ってみよう&lt;br /&gt;
&lt;br /&gt;
==  Ubuntu ==&lt;br /&gt;
&lt;br /&gt;
=== Ubuntuとは ===&lt;br /&gt;
&lt;br /&gt;
Ubuntu(ウブンツ・ウブントゥ)は数あるGNU/Linuxディストリビューションの中でも特にデスクトップ環境ではトップシェア&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
 [http://www.desktoplinux.com/cgi-bin/survey/survey.cgi?view=archive&amp;amp;id=0813200712407  DesktopLinux.com 2007 Desktop Linux Market survey]&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
の一角に常に入っている持つディストリビューションです。&lt;br /&gt;
Ubuntuは[https://canonical.com/ Canonical社]がバックアップしているディストリビューションであり、商用サポート版もあります。&lt;br /&gt;
名前の由来は南アフリカ共和国のズールー族の使うズールー語で、意味は慈愛・人情といった意味を持つのだそうです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ubuntu の次のような理念を掲げて&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
Ubuntu のサイトにある[https://ubuntu.com/community/mission Mission: To bring free software to the widest audience]のページ&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
活動しています。&lt;br /&gt;
&lt;br /&gt;
* ソフトウェアをダウンロード、実行、コピー、配布、調査、共有、変更、および改善する自由を持てるべきである。&lt;br /&gt;
* すべてのユーザが使いたい言語でソフトウェアを使用できるべきである。&lt;br /&gt;
* すべてのユーザの障がいに関係なく、すべてのソフトウェアを使用できるべきである。&lt;br /&gt;
* 我々(Ubuntu)の哲学は、Ubuntuライセンスポリシーとして、我々が作成するソフトウェア、配布する方法、およびライセンス条項にも反映されている。&lt;br /&gt;
&lt;br /&gt;
そしてUbuntuの掲げる自由とは[https://www.fsf.org/ Free Software Foundation]の掲げる[https://www.gnu.org/philosophy/free-sw.html フリーソフトウェア]で示している自由と同じであるとも説明しています。&lt;br /&gt;
&lt;br /&gt;
ubuntuは[http://www.debian.org/ Debian GNU/Linux]が分岐したディストリビューションで、その最初のリリースは2004年です。もともとDebianは数あるディストリビューションの中でも有力なディストリビューションの1です。Debian をベースにしたディストリビューションなので初めからDebianと同様に安定していました。&lt;br /&gt;
&lt;br /&gt;
ubuntuが登場した時に特徴的だったのは充実したデスクトップまわりの環境です。機能的な面だけではなく、見た目のデザインも他の商用システムに引けを取らないレベルに引き上げられていたことでした。用意されているソフトウェア。またその使い勝手は、既存の商用デスクトップ環境とまったく遜色がありません。そのあたりが急速にデスクトップユーザが伸びた要因でしょう。また、開発のライフサイクルが比較的明確であることも、ユーザにとって導入しやすい要因になったと考えてもいいでしょう。&lt;br /&gt;
&lt;br /&gt;
=== いろいろなUbuntu ===&lt;br /&gt;
ubuntuは、ただ1つのUbuntuのセットを用意しているわけではありません。デスクトップ向けの構成、サーバ向けの構成、デフォルトのデスクトップ環境&amp;lt;ref&amp;gt;Ubuntuのデフォルトでのデスクトップ環境はUbuntu Desktop 11.04でUnityを採用しUbuntu 18.04からGNOMEを採用しています。&amp;lt;/ref&amp;gt;は[http://www.gnome.org/ Gnome]ですが、それをKDEにした[http://www.kubuntu.org Kubuntu]、あるいは簡便なxfceを採用している[http://www.xubuntu.org/ xubuntu](ズブントゥと読む)などがありますし、また、教育用ソフトウェアを中心に構成した[http://www.edubuntu.org edubuntu]、またビデオや音楽などビジュアルやサウンドを扱うソフトウェアを中心に構成した [http://ubuntustudio.org/ ubuntu studio]などもあります。&lt;br /&gt;
[https://www.ubuntukylin.com/ Ubuntu Kylin]は中国政府の情報化を推進する部門である中華人民共和国工業情報化部とCanonicalが共同開発した中国政府公認の中国語版Ubuntuです。&lt;br /&gt;
&lt;br /&gt;
=== Ubuntu インストール ===&lt;br /&gt;
インストールに関しては&#039;&#039;&#039;[[ubuntuインストール]]&#039;&#039;&#039;のページか、下に示すページを参照してください。&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntuマシンインストール方法]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  コマンドを入力してみる ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== manを使いこなそう === &lt;br /&gt;
&lt;br /&gt;
UNIXで最も大切なコマンドはmanであるといっても過言ではありません。manにはじまりmanに終る。それがUNIX的なスタイルといえるでしょう。&lt;br /&gt;
manコマンド自身もオンラインマニュアルを用意しています。ターミナル環境でコマンド &#039;&#039;man&#039;&#039; オプション &#039;&#039;man&#039;&#039; を入力してください。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  $ man man&lt;br /&gt;
  man(1)                  Manual pager utils                 man(1)&lt;br /&gt;
  名前&lt;br /&gt;
        man - オンラインリファレンスマニュアルのインターフェース&lt;br /&gt;
  書式&lt;br /&gt;
        man  [-c|-w|-tZT  device]  [-adhu7V] [-m system[,...]] [-L&lt;br /&gt;
        locale] [-p string] [-M path] [-P pager] [-r  prompt]  [-S&lt;br /&gt;
        list] [-e extension] [[section] page ...] ...&lt;br /&gt;
        man  -l  [-7]  [-tZT  device]  [-p  string] [-P pager] [-r&lt;br /&gt;
        prompt] file ...&lt;br /&gt;
        man -k [apropos options] regexp ...&lt;br /&gt;
        man -f [whatis options] page ...&lt;br /&gt;
  説明&lt;br /&gt;
        man はシステムのマニュアルページャーである。 man に与え ら&lt;br /&gt;
        れる引き数 page は、通常はプログラムやユーティリティ、関数&lt;br /&gt;
        などの名前である。これらの引き数それぞれに対応する マニ ュ&lt;br /&gt;
        ア ル ペ ージが検索・表示される。 section が指定されると、&lt;br /&gt;
        man はマニュアルを検索する対象をそのセクションに限定する。&lt;br /&gt;
        デフォルトの動作では、すべてのセクションを既定の順序で検索&lt;br /&gt;
        し、最初に見つかった page だけを表示する。複数のセクション&lt;br /&gt;
        に同名の page がある場合でも、表示されるのは最初の一つだけ&lt;br /&gt;
        となる。&lt;br /&gt;
        ....... &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
manを使いこなすにはmanのmanを読む必要があります。まずは、&amp;quot;man man&amp;quot;として、じっくり読んで下さい。&lt;br /&gt;
UNIXではコマンドの使い方を覚えるのではなく、コマンドのマニュアルを読むことがUNIXの基本です。&lt;br /&gt;
印刷したものが欲しければ&amp;quot;man -T&amp;quot; の出力をPostscriptプリンタに送れることにより紙に出力できます(ただし紙資源を大量に消費するので、その点は考慮した上で出力して下さい)。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Webサイトで用意されているman === &lt;br /&gt;
&lt;br /&gt;
インターネット上のWebサイトにもmanページが用意されています。例えばkernel.orgのサイトにも[https://www.kernel.org/doc/man-pages/  man ページ]が用意されていますし、ドキュメントを日本語化する日本国内のプロジェクトでも[https://linuxjm.osdn.jp/ 日本語のマニュアル]を用意しています。Debianプロジェクトの[https://manpages.debian.org/ manページ]では検索するとブラウザで設定されている言語で判別して英語、日本語、中国語のマニュアルが表示されます。&lt;br /&gt;
&lt;br /&gt;
また歴史的なmanページ[http://man.cat-v.org/unix-1st/ Unix First Edition Manuals] やmanページについての[https://manpages.bsd.lv/history.html 歴史]も公開されているので歴史を知る上で参考にすると良いでしょう。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|2]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=OS%E8%AA%95%E7%94%9F%E3%81%8B%E3%82%89Linux%E3%81%BE%E3%81%A7%E3%81%AE%E6%AD%B4%E5%8F%B2&amp;diff=1716</id>
		<title>OS誕生からLinuxまでの歴史</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=OS%E8%AA%95%E7%94%9F%E3%81%8B%E3%82%89Linux%E3%81%BE%E3%81%A7%E3%81%AE%E6%AD%B4%E5%8F%B2&amp;diff=1716"/>
		<updated>2022-02-17T05:08:53Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 脚注 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;; 注意:   本文は1994年にソフトウェアデザイン誌に連載していたOS入門の原稿をベースにしています。ですからこの文章は1994年当時の状況をベースにしてかかれています。現在ではGNU/Linuxをシステム全体、Linuxをカーネルと区別しますが、本文中ではGNU/LinuxシステムをLinuxと呼んでいます。これは1994年当時の状況をそのまま残しているためです。&lt;br /&gt;
&lt;br /&gt;
== OS誕生 ==&lt;br /&gt;
&lt;br /&gt;
OSの歴史は、コンピュータが産まれてから20年ほど経った1960年代中期からスタートします。1960年中期にIBMが開発した商用コンピュータ・システム [http://www-03.ibm.com/ibm/history/ibm100/us/en/icons/system360/ IBM System/360]は、本格的なOS (OS/360)を搭載していました。それ以前のコンピュータ・システムは、部分的にはOSとしての機能を満たしたものがありますが、OS として機能及び概念が確立はしていません。IBM System/360が始めてOSの機能と概念を確立させました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:60年代のアメリカは公民権運動、ベトナム反戦運動、ウッドストックなどを後世に残すと同時にOSも後世に残したのでした。 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
それまでのIBMのコンピュータは、そのハードウェアの製品ライン毎にソフトウェアが必要で、各々の製品ラインの違うコンピュータ・システムには、ソフトウェアの互換性がありませんでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これは、私たちが現在、アプリケーション・プログラムと呼んでいるような、ある特定目的のために動作するソフトウェアが、OSというクッションを持たず、システム全体のソフトウェアと密接に絡み合っていたからです。つまり、アプリケーションがリソースを管理しなければならなかったのです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
例えば、事務には事務専用システムおよびソフトウェアを、科学計算には科学技術専用システムおよびソフトウェアを用意していました。また、同じ専用システムでも最大メモリやプロセッサのスピード、IOデバイスの数などのシステムの構成が違えば、それだけでソフトウェアの互換性は保てませんでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
OSを導入することによってリソース管理をアプリケーションから切り離します。以前のシステム構成に特化したソフトウェアしか動かないコンピュータ・システムの世界から今度は色々なソフトウェアを動かすことができる、汎用なコンピュータ・システム世界に変化していきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
その後System 360は、370、4300、3080、3090といったIBMシリーズに続き継がれます。それらのシステムは『汎用機』と呼ばれるコンピュータ・システムの代表です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== MULTICSも忘れちゃいけない ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
同世代で、忘れてはいけないのがタイムシアリング・システムと呼ばれる処理方法を用いたCTSSと、それに引き続く今日のOSの原型でともいえるMULTICS&amp;lt;ref&amp;gt;http://www.multicians.org/&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;http://web.mit.edu/multics-history/&amp;lt;/ref&amp;gt; です。CTSSは1963年にMITで使われていた原始的なOSでIBM System / 360よりも古いIBM 7094というシステム上で実現されています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
タイムシアリング・システムとは、複数のユーザが実行している各々のプログラムの処理をある一定時間毎(あるいは入出力が発生しI/O待ちになった場合)に切替えて、各々のユーザがあたかも同時に1つのコンピュータを使っているかのように見せかせるシステムです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CTSSのプログラムの切替えは非常に単純です。ユーザの動かしているプログラムをまるごと主記憶装置から補助記憶装置に追い出し、次に動かすプログラムをロードしてくるというものでした&amp;lt;ref&amp;gt;これは、まだマルチプログラミングまで進化していません。混同しやすいので要注意のこと。 &amp;lt;/ref&amp;gt;。複数のプログラムを切替える能力はありましたが、リソース管理という点では、OSと呼ぶには十分ではありません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
CTSSがうまくいったので1965年にMITとAT&amp;amp;Tベル研究所とジェネラル・エレクトリック社&lt;br /&gt;
&amp;lt;ref&amp;gt;当時のジェネラル・エレクトリックは大手コンピュータ・ メーカーであった。 &amp;lt;/ref&amp;gt;&lt;br /&gt;
が、共同で、現在のOSと比較しても見劣りしないような数々のスペックを持った、多目的なOSを作ろうとしました。それがMULTICSです。現在、私たちがOSの機能と呼んでいる数々の機能はMULTICSで現れたものです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
がしかし、1965年当時それらを実現するにはそもそもハードウェアの能力が足りませんし&lt;br /&gt;
&amp;lt;ref&amp;gt;あまりに古くて、正確な資料がないのですが、MULTICSのターゲッ ト・ハードウェアだったGE-645の処理パワーは、i386マシンぐらいだっ たようです。 &amp;lt;/ref&amp;gt;&lt;br /&gt;
、それだけのアイデアを完全に実現するだけのソフトウェア技術もまだ存在しないという、かなり無謀なプロジェクトでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
途中でベル研がプロジェクトから抜け、ジェネラル・エレクトリック社がコンピュータ市場自体から撤退しました。MULTICSはその後、MIT内部と数十のサイトで利用されました。おどろくことに細々とまだ存在しているのですが&amp;lt;ref&amp;gt;これはこの文章が最初にかかれた1994年の話です。最後のMulticsは2000年10月30日に停止しました。https://multicians.org/history.html#finalshut　&amp;lt;/ref&amp;gt;、多くの人の記憶からは既に消え去ってしまっています。しかしMULTICSで考えられた数々のアイデア、例えば、仮想記憶、プロセスの概念、プロテクションの概念、他にも多くの重要なアイデアが、今日のOSの中に生きています。&lt;br /&gt;
&lt;br /&gt;
== UNIX誕生! ==&lt;br /&gt;
&lt;br /&gt;
MULTICSプロジェクトにはベル研のKen ThompsonとDennis Ritchieがいました。彼らはベル研に戻り、廃棄同然のDEC PDP-7という小型のコンピュータの上に OSを書きます&lt;br /&gt;
&amp;lt;ref&amp;gt;Ken ThompsonはMultics上で動いていたSpace Travelというゲームをベル研に持ち帰ってきたはいいがのですが、Multicsに使われていたコンピュータGE635を使おうとすると一回$50ドルかかるため、ほとんど使われていないDEC PDP-7をみつけてきて小さなOSを書きゲームを動かしはじめます。 参考: https://www.bell-labs.com/usr/dmr/www/spacetravel.html &amp;lt;/ref&amp;gt;。&lt;br /&gt;
1968年のことです。それはMULTICSのような大きなスペックを持つOSではなく、もっとコンパクトなOSなので、彼らはMULTICSをもじってUNICSと命名します。後にUNICSはUNIXと改名し、そのままの名前が定着します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たまに『UNIXはMULTICSの否定である』とか、その反対に『MULTICSの後継がUNIXである』とか書いてある説明を見かけます。これは正しくもあり間違ってもいます。思い出して欲しいのですが今日的なOSの基礎となる沢山のアイデアが導入されているのがMULTICSです。つまり今日的なOSの多くのアイデアそのものはMULTICSを源流にもちます。ただし、MULTICSは、たくさんのアイデアをつめこんだためにシステムが肥大化しプロジェクト自体は失敗に終っています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
もちろん今日的OSであるUNIXにはMULTICSの数々のアイデアが採り入れています。しかしながらUNIXはMULTICSの最大の特徴(かつ致命的な問題となっていた)である多目的で複雑である部分を否定しています。言うまでもないですがUNIXはMULTICSをもう一度作ろうとしたものでもありません。もしUNIXと MULTICSの関係性を表現するとするならば「MULTICSの失敗を教訓にしたOS」と言えるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ちなみにMULTICSが複雑で大きなOSでUNIXがシンプルで小さいOSだったというのは初期のUNIXを指していうことであって、現在の基準では当てはまりません。その後のUNIXは肥大化の道を歩んでいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
現在、UNIXを作ったKen ThompsonやDennis Ritchieといったベル研の人達は既にUNIXは利用せずPlan9という異なるタイプの新しいOSを開発し、利用しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== BSDへの分岐 ===&lt;br /&gt;
&lt;br /&gt;
PDP-7の上で産声をあげたUNIXは、まだ正式なバージョンが付けられていません。ですから、正確にはまだUNIXではないとしてカッコつきで(PDP-7)として分類している本もあります。First Editionと呼ばれるのは、PDP-11/20上で動き始めたUNIXからです。それまでアセンブラで書かれていたUNIXがCで書き換えられFourth Editionとなります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どうしてEditionという言葉を使っているかというと、ベル研究でのバージョンはマニュアルのバージョンで区別しているのだそうです。なぜなら、いつもUNIXのソースコードに手を入れていたため常にソースコードが変わっていてソースコードでのバージョン管理は不可能だったためだそうです。唯一のバージョンコントロールというのはマニュアルだったというわけです。一般には Sixth Edition と言わずにV6 (Version 6)という具合にVersion を使う方を目にする方が多いかも知れません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1976年のSixth EditionをベースとしてUNIXはPWB3.0とBSDが分岐します。PWB はProgrammer Work Banechの略です。この流れは、後にSystem IIIへつながります。BSDはBerkeley Software Distributionsの略で、UCB (University of California Berkeley)のCSRG (Computer System Research Group)で作られていました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1BSDと呼ばれる、最初のバージョンはPDP-11上で動いていました。これが2BSD になり2.xBSDになります(xは1,2,3といった数字が入ります)。2.xはPDP-11をプラットフォームにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一方、2BSDからVAXで動く3BSDに分岐し、後に4.0BSDになります。以降、 4.1BSD、4.2BSD、4.3BSD、4.4BSDとなります。もともとのUNIXのプログラムワークベンチとしての使い勝手の良さはもとより、CSRGで加えられた仮想記憶の能力、高速なファイルシステム、TCP/IPの実装プラットフォーム&lt;br /&gt;
&amp;lt;ref&amp;gt;これらの研究は国防総省傘下の研究組織であるDARPAからの研究資金の援助で開発されています。&amp;lt;/ref&amp;gt;&lt;br /&gt;
などの数々の最新技術の投入によるアドバンテージにより、BSDは研究所や大学を中心に急速に広がります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
BSD自体は自由にコピーできるのですがベル研で作られたコードが含まれていますので、UNIXを動かすにはAT&amp;amp;Tへのライセンス費用が発生しました。この1980年代前半、AT&amp;amp;Tへのライセンス費用は研究施設では配布実費程度($800)、商用サイトでは($43000)でした。しかしながら高額な科学計算用コンピュータ VAXを所有している所では、この料金は大した問題ではありませんでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
最後のリリースが4.4BSDです。ここでCSRGでのBSDの研究開発は終了します。この頃になるとBSDは技術的に研究と呼べる部分が少なくなってきたのは確かですが、それ以上にAT&amp;amp;Tとライセンセンス問題がこじれて研究者の中のモチベーションが保てなくなったのではと筆者は考えています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1992年1月、UNIXライセンスを管理するAT&amp;amp;Tの子会社URL社が4.3BSD NET/2をベースに商用BSDを作ったBSDI社を相手に製品出荷差し止め訴訟をおこします。それが判事に却下されたので、今度はUCBとBSDIの両方を相手に製品出荷差し止め訴訟を繰り広げます。また裁判途中でURL社がAT&amp;amp;Tからノベル社に買収されたりとったこともあって、なかなか訴訟も、和解案も進みません。やっとのこと1994年の1月に解決します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
貴重なCSRGメンバーの労力が、このバカバカしい訴訟で浪費されたといっても過言ではありません。1995年6月の4.4BSD-Lite Release 2を最後にCSRGは解散します。もちろん表向きは「新しい時代、新しい人達へのバトンタッチ」ですが、実際は、この世にもバカバカしい訴訟で燃え尽きたといっても過言ではないでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== まぼろしのSystem IV ===&lt;br /&gt;
&lt;br /&gt;
Sixth Editionから分岐してPWBが作られます。ベル研にはリサーチとは関係のないUNIXをソフトウエアの開発のために使おうというグループがあって、そこがUNIXをプログラマーのための道具として使うためのに改良しました。 1979年のことです。これがPWB/UNIX 1.0として研究所の外部にもライセンスされるようになります。PWBから分岐して1982年にSystem IIIが作られます。PWB はその後何度かバージョンがアップされますが、1984年にSystem V Relase 2 に統合されます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一般市場向けに販売された最初のAT&amp;amp;TブランドUNIXがSystem IIIです。筆者は1983,4年頃にCPUにMC68000を使ったNCR社製マシンでSystem IIIを使った経験があります。GUIもネットワークもありませんが、使い心地は今のLinuxや FreeBSDなとどおなじです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
その後、後継バージョンとしてSystem Vが出てきます。System IVという名前は幻になっています。実は発売寸前までSystem IVは進んでいたのですが、その内容のひどさにUNIXを生み出したベル研のメンバーは激怒し「今後一切関係はない」といって、マニュアルなどすべてから名前の削除を求めたそうです。それでSystem IVは余儀なく大量の変更が発生し、発売できなくなりました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 世界最大のUNIXベンダ マイクロソフト === &lt;br /&gt;
&lt;br /&gt;
1980年代前半、世界で最もUNIXの出荷が多かったのは実はマイクロソフト社でした。その頃、SCO (Santa Cruz Operation)社と共同でマイクロソフトは XENIXというIntel 8086上で動くUNIXのバージョンを作成していました。その頃、他はVAXのような大きなマシンばかりでしたので、出荷数から見るとXENIX の数が最大のように見えるのです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== UNIXの人口爆発 ===&lt;br /&gt;
&lt;br /&gt;
1985年から1995年までの10年間は、色々なバージョンのUNIXが増殖した時代といえるでしょう。UNIXの流行とともに、色々な会社が色々なUNIXを実装して売り出していきます。日本でも通産省の大失敗プロジェクトであるΣプロジェクトが行われていた頃です。色々な会社のUNIXマシンを製造し、少しでも自分のシェアを独占しようと奔走していたころです。このような背景があってAT&amp;amp;Tが BSDIの邪魔をし、その邪魔ができないと見るやいなや、UCBも含めて訴えていた頃です。なんと情けない時代でしょう。そんなAT&amp;amp;Tや他の企業のドタバタも 95年以降は鎮静化します。理由は簡単です。Windows がディスクトップUNIXのシェアを食い、Windows NTがサーバのシェアを食ったからです。&lt;br /&gt;
&lt;br /&gt;
== Linux ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Linuxの誕生前夜 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxが生まれる1991年前夜、既にOSのトレンドは新しい世界に入っていました。それはマイクロカーネル技術を使ったOSです。マイクロカーネルのポイントは提供するサービスと、最小限のコントロールのみしか残していない小さなカーネルから出来上がっている所です。 最小限のコントロールとは、メモリ、タスク、プロセス間通信、(最小限必要なハードウェアの)デバイスドライバなどです。ファイルシステム、ネットワーク機能、プロセス管理、仮想記憶管理などなどはサーバプログラムとして動作しています。それまでのUNIXカーネルはOSが果たすべき機能はすべて1つのカーネル内で行われているモノリシック・カーネルとよばれるタイプでした。&lt;br /&gt;
&lt;br /&gt;
=== Linux誕生 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
フィンランドの大学生 Linus Torvaldsが1991年にLinux version 0.02をリリースしました。1994年にLinux 1.0をリリースしました。 Linuxを一躍有名にしたのは、使い勝手でもなく、新規性でもなく、処理能力でもありません。1992年にあったネットニュース上での大喧嘩でした。&lt;br /&gt;
&lt;br /&gt;
=== Torvalds vs. Tanenbaum ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1992年にcomp.os.minixで行われたLinuxの生みの親Torvaldsとオペーレーティングシステム研究者の大御所Tanenbaum教授との論争です。&amp;quot;Linux is obsolete&amp;quot;というタイトルで書いた教授の記事の趣旨は「90年代に70年代の技術であるモノリシックカーネルであること」「ポータビリティに欠けること」の2点です。これは&lt;br /&gt;
オープンソフトウェア&amp;lt;ref&amp;gt;http://www.oreilly.com/catalog/opensources/book/appa.html&amp;lt;/ref&amp;gt;&lt;br /&gt;
(オライリージャパン)に収録されいるので、みなさんも是非1度目を通されることをお勧めします。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
正直に筆者の意見をいうと教授の言い分は正しいです。ただし、その時代遅れな構造こそがLinuxに味方しました。誰もが知っている時代遅れの枯れた技術を使ったからこそLinuxのカーネルをハックできる人口が多く、そしてまた実現方針も建てやすく、早く簡単に作れたといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
マイクロカーネルはモノリシック・カーネルよりオーバーヘッドが発生し処理効率が落ちると言われていますが、これはLinuxができてきた91年であっても古い話です。80年代後半ごろマイクロカーネルの草分けであるMachはのオーバーヘッドの問題はありましたが90年に入るとマイクロカーネル技術は既に、その問題を克服しています。いまだにこの「マイクロカーネルは遅い」という神話を信じている人がいて驚くことがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
またマイクロカーネルの提供する「粒度」というモノリシックカーネルでは存在しえない概念も入っています。ここでの粒度とはマイクロカーネルが実行する処理のサイズだと考えてください。マイクロカーネルはこの粒度という処理を分散する考え方を導入しているためたとえばCPUを何十、何百、何千個搭載した並行処理マシン上で1つ1つのCPUでマイクロカーネルが各々動き、個々のタスクが割り当て、さらに全体としてプロセスを管理するプロセス管理サーバがあるような実装が可能になります。たぶん、このようなことをしたいために日立の並列スーパーコンピュータ SR8000シリーズ の OS は Machをベースとしたマイクロカーネルで実装しています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Windows NTもマイクロカーネルで作られているので同じような効果がでます。たとえばCOMPAQ ProLiant 8500というマルチプロセッサマシンを多数と Microsoft Windows 2000 Advanced Server と Microsoft SQL Server 2000 Enterpriseの組合せでデータベースのベンチマークであるTPC-Cの最高レコードを何度か書き換えています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2とか4程度のプロセッサ数ならモノリシックカーネルでも使えるでしょうが、このようなプロセッサ数が多いマルチプロセッサマシンでは上手に動けません(このような劇的なパフォーマンスが出る実装はまだ存在していません)。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== LinuxはUNIXではない ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
こう書くと混乱する人がいるかも知れません。まずLinuxはUNIXではありません。BSDにしても、他の多くのUNIXベンダのOSにしても、前身となるUNIXシステムがあるものがほとんどです。その前身をたどっていくと、最後はベル研の UNIXにたどり着きます。Linuxは、その流れから完全に独立しています。現在のLinuxの原点は、今や伝説ともなったLinus Torvaldsというフィンランドの1 大学生が386CPUベースのPC上で勉強のために作り始めたものです。それ以前をひきついでいません。LinuxはLinuxから出発しているのです。つまり元祖なのです。これは、かなりユニークなポジションにいます。たとえばThe Design and Implementation of the 4.4BSD Operating SystemのHistory of the UNIX Systemの章にあるUNIXの家系図を見ると、前身がないOSはPlan9とLinuxしかありません。 家系図の解釈にはいろいろな流儀があり、たとえばPlan9がUNIX V8から分岐したとか、Linuxがminixから分岐したと表現しているものがあります。しかし、影響を受けたというならまたしも、これらのあいだではソースコードの流用はありません。&lt;br /&gt;
&lt;br /&gt;
=== LinuxはUNIX互換ではない ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
LinuxはUNIX互換として作られたわけではなくPOSIX 1003.1仕様のOSです。 POSIX 1003.1とはポータブルOSの互換性を保つための規格です。POSIX 1003.1 はUNIXを参考にして作られていますがUNIXの規格([[UNIXとは何か]]を参照)ではありません。よって POSIX 1003.1準拠のOSであるLinuxはUNIX互換ではないということです。&lt;br /&gt;
&lt;br /&gt;
=== LinuxはLinuxではない ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
システムはカーネルだけあっても、何もサービスはできません。サービスを行うためのソフトウェア環境が揃って始めてシステムとなります。その取り巻く環境をミドルウェアと呼ぶ場合もありますが、ここではもっと広い意味でユーザにサービスを提供する総体としてシステムと呼びます。Linuxはカーネルです。そのカーネル上でサービスを提供するための数々のソフトウエアはフリーソフトウェアであるGNUが使われています。よってシステムとして呼ぶ場合は GNU/Linuxと呼ぶのが正しい呼び方です。&lt;br /&gt;
&lt;br /&gt;
===  Linuxは新しいOSなのか ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
誕生した時期は「新しい」と言えますが、その中身の構造は非常に「古典的」です。それはTanenbaumがLinuxを切捨てた通りです。ではLinuxの目標は何なのでしょうか?それは「POSIX準拠した本格的な機能を持ったフリーのOSを作ること」だと言えます。技術的野心に燃えて新しいことをするのではなく、自分達が自由に使えるOSを作るということが明確だったのです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Torvaldsは最初は、そんなに目標が明確だったわけではなかったと思います。しかし、Torvalds vs. Tanenbaumの論争の中でLinuxの方向性は決っていきます。それは完全にフリーソフトウェアであること、将来の発展よりまず現在のマシン上で十分に動かせることです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
フリーソフトウェア運動の指導者リチャード・ストールマンがGNUプロジェクトの性質に対してこういったのを筆者は聞いたことがあります。「GNUソフトウェアはわくわくするような新しいものを研究し画期的なソフトウェアを生みだすためのプロジェクトではない。ソフトウェアをフリーなものに置き換えるむしろ後追いの地味なプロジェクトだ」&lt;br /&gt;
&lt;br /&gt;
=== なぜLinuxがこれだけ広まったか ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Linuxが現れた頃、既に同様にフリーである386BSDがありました。しかしLinux の開発の方が一歩リードしていたようです。FSFの機関誌であったGNUダイジェストのバックログをおってみるとよくわかります。386BSDとLinuxがGNUダイジェスト(GNU&#039;s Bulletin)に紹介されるのは、1992年6月発行の13号です。&amp;lt;ref&amp;gt; GNU&#039;s Bulletinは次のURLから入手できます。ftp://ftp.sra.co.jp/pub/gnu/sra/Bull-j/ アクセス出来ない場合はコピー版を参照ください。 http://uc2.h2np.net/misc/bull13j.txt&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
GNUダイジェスト1992年6月号から引用してみましょう。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;BLOCKQUOTE&amp;gt;&lt;br /&gt;
* Linux (386マシン用のフリーなUnixシステム)&lt;br /&gt;
:Linux (Linus Torvalds にちなんで名前が付けられた) は、フリーな Unix シス テムのクーロンであり、System V や POSIX の機能のサブセットを実現する。 Linux はまったく最初から作成され、カーネル内には独占的なコードを含まない。 非常に多くのユーティリティやライブラリは、GNU ソフトウェアを使っている。 Linux は 386/486 AT バスマシンでのみ動作する。Intel 386 以外への移植は非 常に困難であろう。カーネルで広範囲に、386 メモリ管理システムやタスク・プ リミティブを使っているからである。Linux は次のサイトから anonymous FTP で入手可能である。`tsx-11.mit.edu:/pub/linux&#039; (アメリカ)、 `nic.funet.fi:/pub/OS/Linux&#039; (ヨーロッパ)。 Linus に関して討論する `comp.os.linux&#039; というニュース・グループがあ る。メイリング・リストに関する問い合わせは `linux-activists-request@niksula.hut.fi&#039; まで。&lt;br /&gt;
&lt;br /&gt;
* フリーな 386 BSD&lt;br /&gt;
:経験のあるハッカーは、William F. Jolitz らによって移植された BSD Unix の 386 へ移植したバージョンのアルファ・テストに興味を抱くかもしれない。この カーネルは AT&amp;amp;T コードを含まないフリーなもので、自由に再配布可能である。 詳細な情報は `sokol@reyes.stanford.edu&#039; から入手可能である。初 期のバージョンは安定していないので、あるシステムではブート時に問題が発生 する点に注意されたい。&lt;br /&gt;
&amp;lt;/BLOCKQUOTE&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここからわかるのは、386BSDよりもLinuxの方が安定して動作していることと、既にftpサーバが用意されていて、誰でも容易に入手できる体制がアナウンスされていたことです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この文章からもLinuxはIntel CPUアーキテクチャーにべっとり依存していたことがわかります。この頃のUNIXユーザはパワーのないPCアーキテクチャーのマシン、いわゆるパソコンなど使わず、SUNやVAXといったワークステーションを使っていました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
教科書通りの考え方だと単一アーキテクチャーしか使えないOSかつ、パワーないCPU上でしか動かないOSなので魅力がなさそうに見えます。ところが、実際は既にたくさんのPCが世の中に存在していて、かつ、その後のウインテルと揶揄されるWindowsとIntel CPUの組合せでIntel CPUの能力が格段に発達しました。その時流にLinuxはちょうど乗っかったのです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
386BSDは4.3BSD NET/2からブランチしています。ここが利用者を躊躇させる1 つの要因になったようにみえます。既に本家4.3BSD NET/2は4.4BSDへアップするための作業が進んでいました。その後、386BSDはFreeBSDとNetBSDという2つにカーネルが分岐してしまいます。また本家4.4BSD自体がIntel CPUをサポートする予定です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このような状況でユーザはどれがステーブルなBSDであるかを選択できるでしょうか。筆者なら386BSD(FreeBSDやNetBSD)を選択しません。4.4BSDまで待ちます。一方で、今、手元にあるPCでフリーのUNIXを使いたいと思ったら? 筆者なら将来のマップが見えない386BSDよりもLinuxを選びます。筆者の目からみれば、出発点で技術的に不利と思われていたLinuxですが、今振り返ると広がるべくして広がったように見えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1994年以降 ==&lt;br /&gt;
&lt;br /&gt;
1994年以降のLinuxの繁栄に関しては筆者よりもきっとSoftwareDesignの読者のみなさんの方が色々な情報を知っていると思います。ではLinuxの現代史は、また別の機会に。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このページへのショートURL:  http://uc2.h2np.net/i/d1.html&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|1]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=UNIX%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1715</id>
		<title>UNIXとは何か</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=UNIX%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1715"/>
		<updated>2022-02-17T05:08:22Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 脚注 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== UNIXとは何か ==&lt;br /&gt;
===  UNIXの定義 === &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXは1969年にベル研究所のKen Thompson、Dennis Ritchieらが作ったオペレーティングシステムの名前です。最初はわかりました。では、「現在のUNIXの定義は?」と聞かれた場合、どのような答えが帰ってくるでしょうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 1969年に作られたUNIXを源流にもつもの&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはなかなかわかりやすい定義です。ほとんどすべてのUNIXの仲間と呼ばれるオペレーティングシステムに当てはまります。しかしながら、GNU/LinuxはオリジナルのUNIXを源流に持ちません。GNU/Linuxのカーネルは最初Linus Torvaldsがゼロから書き始めたものです。しかしだからといってUNIXらしいGNU/LinuxをUNIXの仲間から排除はできません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* （現在The Open Groupが保持している）商標の利用許可を過去に得ていたもの&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* The Open Groupの定めるUNIX標準仕様を満たし、それをThe Open Groupが認めたもの&amp;lt;ref&amp;gt;[http://www.opengroup.org/membership/forums/platform/unix The UNIX® Standard]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIX標準仕様とは、The Open Groupが定めるThe Single UNIX Specificationのことです&amp;lt;ref&amp;gt;2018年現在は &#039;&#039;SINGLE UNIX® SPECIFICATION, VERSION 4, 2018 EDITION&#039;&#039; となっています。何年かに一度改定されるので最新の規格は Open Group のサイトで確認してください。&amp;lt;/ref&amp;gt;。これを取ると商標としてのUNIX(R)を利用できるようになることができます。これをUNIXの定義とすると &amp;quot;OS X version 10.11 El Capitan&amp;quot; や  &amp;quot;Solaris 10 Operating System&amp;quot; や  &amp;quot;AIX 6 Operating System V6.1.2 with SP1&amp;quot;などはUNIXですが、FreeBSDやGNU/Linuxは、UNIXでなくなってしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* IEEE Std 1003.1 (POSIX 1003.1) 準拠あるいはISO/IEC 9945 準拠のもの&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IEEE Std 1003.1 とISO/IEC 9945は内容的に同じものですが、これらの仕様に準拠したものがUNIXであるといえば、技術的な意味において間違いはありません。Microsoft社のオペレーティングシステムでも過去にWindows NT 4.0においてIEEE standard 1003-1:1990の仕様を満たしたサブシステムを持っていました&amp;lt;ref&amp;gt;POSIX and UNIX Support in Windows&lt;br /&gt;
https://social.technet.microsoft.com/wiki/contents/articles/10224.posix-and-unix-support-in-windows.aspx&amp;lt;/ref&amp;gt;。ではWindows NT 4.0はUNIXなのでしょうか？少なくとも筆者はUNIXと呼ぶことには抵抗感を覚えます。&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;調べてみよう&#039;&#039;&#039;&lt;br /&gt;
: IEEE Std 1003.1 とはどんな規格なのか調べてみよう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* UNIXの思想や文化を継承するもの&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
UNIXの思想や文化を継承するものといいますが、その思想や文化とは何を指しているのでしょうか。ここはDon Libes と Sandy ResslerのLife with Unix&lt;br /&gt;
&amp;lt;ref&amp;gt; Life with UNIX―UNIXを愛するすべての人に, ドン ライブ (著), サンディ レスラ (著), 福崎 俊博 (翻訳), 坂本 文 (翻訳),  ISBN 4756107834 &amp;lt;/ref&amp;gt;&lt;br /&gt;
本を参考にしてまとめてみます。&lt;br /&gt;
&lt;br /&gt;
=== UNIXの思想 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 小さいことは美しい ～ 問題は小さく分割し、個々に解決する小さいコマンドを使い、それを組み合わせて全体の問題を解決する。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 20%の労力で80%を解決する ～ すべての問題を万能に解決するようなシステムを目指さない。労力少なく、おおよその問題を解決する。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 単純に保て ～ 単純であるべきものは単純にしておく。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
こんな風に考えるのがUNIX流だといえるでしょう。実はこれらは別にUNIX独自の思想ではなく、既に社会にある考え方です。&lt;br /&gt;
「小さいことは美しい」は経済学者 E. F. Schumacher の著書&amp;quot;Small Is Beautiful : Economics as if People Mattered&amp;quot;&lt;br /&gt;
&amp;lt;ref&amp;gt; Small Is Beautiful: Economics as if People Mattered ,  1989/6/1, E. F. Schumacher (著), ISBN 0060916303 &amp;lt;/ref&amp;gt;&lt;br /&gt;
&amp;lt;ref&amp;gt; スモール イズ ビューティフル (講談社学術文庫) 文庫 – 1986/4/7, F・アーンスト・シューマッハー (著), 小島 慶三 (翻訳), 酒井 懋 (翻訳) ISBN 4061587307&amp;lt;/ref&amp;gt;&lt;br /&gt;
の考え方です。&lt;br /&gt;
「20% / 80%」はイタリアの経済学者 V. Paretoのパレートの法則です。&lt;br /&gt;
「単純に保て」は&amp;quot;Keep It Simple(Stupid)&amp;quot; は、エンジニアの口伝伝承であるマーフィーの法則の1つとして知られています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ただ、これが現在のGNU/Linuxのシステム、あるいはLinuxカーネルにも当てはまるかは、筆者は少々疑問です。今のLinuxカーネル一つ取っても、たくさんの参加者によって組み込まれた、非常に多肢に渡る色々な機能を持っています。何でも投げ込むキッチンシンク（流し台）になっています。&lt;br /&gt;
コードからみた場合、「小さいことは美しい」とか「単純であるべきものは、単純であれ」という部分はかなり怪しくなってきています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
実際 UNIX をベル研で開発していた人たちは UNIX System V の時には UNIX 捨て、 UNIX のオリジナルのアイデアを徹底させ、さらに新しく展開した[https://9p.io/plan9/ Plan 9]というオペレーティングシステムを開発していました。&lt;br /&gt;
&amp;lt;ref&amp;gt; Plan 9 from Bell Labs Fourth Edition https://9p.io/plan9/ &amp;lt;/ref&amp;gt;&lt;br /&gt;
むしろこちらの方がUNIXのオリジナルコンセプトに忠実だと筆者は考えるほどです。&lt;br /&gt;
であれば、現在UNIXと呼ばれているもの自体が既にUNIX的ではなくなってしまっているという不思議な結論に達してしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように、どこまでがオペレーティングシステムなのかという問題と同じく、 UNIX の定義もどこまでが UNIX なのかの境界線がはっきりとしない問題だと言えるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;調べてみよう&#039;&#039;&#039;&lt;br /&gt;
:色々なUNIXの定義を見つけてみよう。また自分なりのUNIXの定義をしたならば、どんな定義になるだろうか。&lt;br /&gt;
&lt;br /&gt;
=== ここまでの歴史 ===&lt;br /&gt;
&lt;br /&gt;
UNIXの歴史に関しては Éric Lévénez氏が管理する&#039;&#039;&#039;UNIX History&#039;&#039;&#039;というサイトを参照してください。UNIXの過去から現在までにいたるまでのタイムラインチャートなど色々と参考になる資料があります。&lt;br /&gt;
&lt;br /&gt;
* http://www.levenez.com/unix/&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|1]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
	<entry>
		<id>https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1714</id>
		<title>オペレーティングシステムとは何か</title>
		<link rel="alternate" type="text/html" href="https://uc2.h2np.net/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B&amp;diff=1714"/>
		<updated>2022-02-17T05:07:31Z</updated>

		<summary type="html">&lt;p&gt;Hironobu: /* 脚注 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== オペレーティングシステムとは何か == &lt;br /&gt;
&lt;br /&gt;
===  オペレーティングシステムの再確認 === &lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムとは何かを基本に戻って再確認してみましょう。&lt;br /&gt;
オペレーティングシステム( Operating System )を短く説明すれば、文字通りコンピュータを操作してゆく&lt;br /&gt;
(Operating/オペレーティング)&lt;br /&gt;
体系&lt;br /&gt;
(System/システム)&lt;br /&gt;
です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムの役目は次の３つの目標を達成するためにリソース&lt;br /&gt;
(Resources : 資源 )&lt;br /&gt;
と、&lt;br /&gt;
アプリケーション&lt;br /&gt;
( Applications : ユーザが使うソフトウェア )&lt;br /&gt;
の間に存在し両者を結び付けるための糊の役目をするソフトウェア群であるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* リソースを効率的に利用し、また管理をする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションが直接リソースを制御する必要をなくする&lt;br /&gt;
&lt;br /&gt;
* アプリケーションにとってリソースをさらに抽象化する&lt;br /&gt;
&lt;br /&gt;
=== リソースとは === &lt;br /&gt;
&lt;br /&gt;
リソースとは、コンピュータ上にある、処理を行なう際に必要となる資源を意味する概念的なものです。&lt;br /&gt;
リソースとしてハードウェアリソースとソフトウェアリソースの2つはすぐに思い浮かぶでしょう。&lt;br /&gt;
さらに一歩踏み込んでオペレーティングシステムはコンピュータ・システムを利用するコストをより少なくするための道具と考えるならば、&lt;br /&gt;
利用者や運用者などを指してヒューマンリソースとしリソースの中に含める必要が出てきます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
つまりハードウェアリソース、ソフトウェアリソース、ヒューマンリソースを有効に使うための役割がオペレーティングシステムには求められます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 捕捉 :  一口にコストといってもいろいろな場面でのコストがあります。また数値に現れるコストだけではなく、数値に現れにくく把握するのが難しいコストもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
以下に色々なリソースについて考えてみましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== ハードウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ハードウェアリソースにはCPU、主記憶装置(メモリ）、補助記憶装置、入出力装置、ほかがあります。&lt;br /&gt;
&lt;br /&gt;
===== CPU =====&lt;br /&gt;
&lt;br /&gt;
CPU( Central Processing Unit : 中央演算処理装置 ) : 命令を実行し、演算を行なうユニット部分です。少し前までは、CPUの説明といえば、プロセッサチップを示せば終だったのですが、最近の高性能のプロセッサチップは、少々複雑になっています。現在のプロセッサチップは、キャッシュ記憶ユニットという高速に記憶を取り込むための、短期間だけ記憶を保持しているような記憶装置も内蔵しています。それ以外にも多くの機能を詰め込んでいます。そこまで分割していくと話が混乱しますので、ここでのCPU はプロセッサチップという具体的な製品ではなく、命令を実行し演算を行なうユニットという抽象的な役割部分だと理解してください。以降、他のCPU説明でも同じです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== 主記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
主記憶装置 ( Main Memory Unit ) : いわゆるメモリのことです。&lt;br /&gt;
CPUと直接やりとりする記憶装置を指します。&lt;br /&gt;
演算のための値を記憶しておく、結果を記憶しておく、命令を記憶しておくなどといったために使われます。&lt;br /&gt;
以前は、単純にCPU ←→主メモリという構造で説明が十分だったのですが、現在での具体的な物理メモリの構成は、アクセスの効率を考え何段階かの動作速度や容量が異なるキャッシュメモリを用意しておき、CPUと記憶をやりとりしています。&lt;br /&gt;
わりきって一言でいうなら電気を切ったら消えてしまう一時的な記憶装置だといえます。&lt;br /&gt;
&lt;br /&gt;
===== 補助記憶装置 =====&lt;br /&gt;
&lt;br /&gt;
補助記憶装置 ( Auxiliary Memory Unit ) : ハードディスクや磁気テープのような装置のことです。&lt;br /&gt;
現在ではコンパクトフラッシュメモリやUSBメモリなどもこのような区分けに入ってきます。&lt;br /&gt;
主記憶装置との違いは、CPUと直接記憶のやりとりを行なわないこと、記憶の容量が大きいこと、長期間記憶&lt;br /&gt;
(わり切って言えば電気を切っても消えない記憶)&lt;br /&gt;
を保持するユニットです。&lt;br /&gt;
&lt;br /&gt;
===== 入出力装置 =====&lt;br /&gt;
&lt;br /&gt;
入出力装置 ( Input/Output Unit ) : キーボード、マウス、ディスプレイといったものや、シリアルポートやパラレルポート、またあるいはネットワークボードといったものなどのがあげられます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:  ハードウェアリソースを構成&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 上 , ジョン・L. ヘネシー (著), デイビッド・A. パターソン (著), 成田 光彰 (翻訳), 2014/12/6, ISBN 4822298426&lt;br /&gt;
&amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;&lt;br /&gt;
コンピュータの構成と設計 第5版 下, デイビッド・A・パターソン (著), ジョン・L・ヘネシー (著), 成田光彰 (翻訳), 2014/12/6, ISBN 4822298434&lt;br /&gt;
&amp;lt;/ref&amp;gt;するものとしてこの他に、どんなものがあるだろうか。&lt;br /&gt;
&lt;br /&gt;
====  ソフトウェアリソース ====&lt;br /&gt;
&lt;br /&gt;
ソフトウェアは、そのコンピュータ上で動くソフトウェアで共有し利用するようなデータ、ライブラリ、プログラムを意味します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
たとえばオペレーティングシステムの心臓部である[[カーネルの構造と機能|カーネル部分]]、アプリケーションが使うライブラリ、あるいはシステムを運用する上で必要なコマンド群などがあげられます。データベースを考えるとアプリケーションとしてのデータベースプログラムとその中に格納されアプリケージョンに利用されるデータから成り立ちます。この両者があってソフトウェアリソースとして提供されるデータベースとして意味をなします。多種多様なソフトウェアリソースがどのような役割を担うのかの議論は後ほどしましょう。&lt;br /&gt;
&lt;br /&gt;
==== ヒューマンリソース ====&lt;br /&gt;
&lt;br /&gt;
人的なリソースです。コンピュータが非常に高価だった頃は、その利用のために人を雇うコストの方が小さいファクタだったため、あまり大きな関心は寄せられていませんでした。&lt;br /&gt;
昔の汎用機時代においては、人的コストよりもハードウェアのコストの方がはるかに高く、そのため人間が便利に使えるよりも、まずハードウェアを最も効率よく使うにはどうするべきかを優先していたのです。&lt;br /&gt;
高性能のコンピュータがコモディティ(日用品)化してしまっている現在では、人的なリソースの方が高価です。人的リソースの効率的利用できるようにすることもオペレーティングシステムには求められています。このように時代の流れでハードウェアのコストが下がるにつれ、人的コストの比率が相対的にあがってきます。このような状況では、今度は人的コストを如何に下げるかが今日の課題となっています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
: &#039;&#039;&#039;調べてみよう&#039;&#039;&#039; : 人的なコストを低減するためにどのような工夫がなされているのだろうか。&lt;br /&gt;
&lt;br /&gt;
== オペレーティングシステムの潮流 ==&lt;br /&gt;
&lt;br /&gt;
時が立つにつれ、どんどんハードウェアが小型化し、また高性能になっていきます。&lt;br /&gt;
例えば、2010 年のデスクトップコンピュータ、いわゆるパソコンと呼ばれる機械の上位機種の計算スピードは、私がこの業界に入った 1980 年半ばのスーパーコンピュータ並、あるいはそれ以上の性能を持っています。この文章を読んでいるこの瞬間では、2010年のデスクトップパソコンなど性能的に時代遅れになっているでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1990 年当時から比較しても、エンジニアリングワークステーションと呼ばれていた数百万から一千万円くらいの価格だったコンピュータシステムよりも遥かに高速です。&amp;lt;ref&amp;gt;RASPBERRY PI 2 MODEL B http://www.raspberrypi.org/products/raspberry-pi-2-model-b/ &amp;lt;/ref&amp;gt;&amp;lt;ref&amp;gt;Iridis-pi: a low-cost, compact demonstration cluster https://www.southampton.ac.uk/~sjc/raspberrypi/raspberry_pi_iridis_lego_supercomputer_paper_cox_Jun2013.pdf&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
当然、そうなってくると、高性能なハードウェアを効率よく動かす、かつハードウェアの能力を引き出すために、かつて高価なコンピュータで使われたいたオペレーティングシステムのテクノロジーが必要になってきます。かくして、身近に高性能なオペレーティングシステム が使われるようになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 現在のオペレーティングシステムへ向かう2つの流れ ===&lt;br /&gt;
&lt;br /&gt;
現在のハードウェアとオペレーティングシステムの関係をハードウェアの歴史の変遷を踏まえて考えてみます。みなさんが使っているデスクトップのコンピュータに至る流れには2つの流れがあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 下から上への流れ ====&lt;br /&gt;
&lt;br /&gt;
小さいものから、大きなものへ変化した様子を見てみましょう。&lt;br /&gt;
1971年に世界初のマイクロプロセッサIntel 4004 が出来てから、パーソナルコンピュータが作られ、どんどん性能が良くなってきた流れです。パーソナルコンピュータ、いわゆるパソコンは初めは玩具のようなものでした。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1975年に発売された世界初のパソコンMITS Altair 8080はIntel 8080 250Khz を搭載しメモリは256byteでした。キーボードもモニターも当然ながらハードディスクなどありません。プログラムはフロントパネルからスイッチを操作し、バイナリーのマシン語を入力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1976年ぐらいになると、Apple、Sol、Altairといった最も初期の頃のパソコンが作られてきます。この頃、Bill GatesとPaul AllenはAltair 8080 (メモリ4KByte版）用に大型汎用機上で動いていたBASIC言語を移植しMITSへライセンスします。翌、1977年には [[Steve Wozniak]] とSteve Jobs &amp;lt;ref&amp;gt; スティーブ・ジョブズ 1 (講談社+α文庫)  ISBN 4062816148 &amp;lt;/ref&amp;gt;がApple Corporationを設立し、また同じくしてBill Gates とPaul Allenは正式にMicrosoft companyを設立します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Apple や Sol や Altairのような初期のパソコンが作られます。スミソニアン博物館にある初期のパソコンたちの写真です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2551.JPG|thumb|220px|Homebrew computer club ]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2548.JPG|thumb|220px|Apple]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2549.JPG|thumb|220px|Sol]]&lt;br /&gt;
&lt;br /&gt;
[[image:IMG_2547.JPG|thumb|220px|Altair]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
1984年にIBMがIBM PCを販売開始した時が、今日のパーソナルコンピュータ隆盛の時代の本格的な幕開けだったといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
初期の頃のパソコンにはオペレーティングシステムがありませんでした。次にCP/MやMS-DOSといった 低レベルな機能しか持たない原始的なオペレーティングシステムが現われます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;補足: 機能が不十分なため厳密にはオペレーティングシステムとは呼べずモニターと呼ぶべきものだと筆者は考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;調べてみよう&#039;&#039;&#039;:オペレーティングシステムの前段階ともいえるモニターとはなんだろうか。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
これはハードウェアの能力が極めて限られているので、大型汎用機のような機能を望むべくもなく、低レベルな機能しか持たざる得ないという限界があります。1990年代ともなると、高速なCPU、大容量のメモリー、大容量のハードディスクなどハードウェアの能力は格段に上がります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし、一方で、そのハードウェア上で動かしているソフトウェアのシステム構造は古い頃から手直し、手直ししてアップグレードしてきたものです。さらにパーソナルな環境ではなく、ネットワークに繋がれ、さらにはインターネットに繋がれるまでになると、玩具の箱から個人のツールとして発展してきた単純なパーソナルコンピュータのモデルではいずれ限界が来てしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように下から上へ向かうトレンドが、まず1つあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 上から下への流れ ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
コンピュータが作られた時から、今日のパーソナルコンピュータが隆盛を究めるまでに至まで常にコンピュータのハードウェアは高価なものでした。&lt;br /&gt;
1960年当時初期までは、コンピュータはプログラムを走らせるために特別なセットアップが必要で、色々なプログラムを走らせることが困難でした。&lt;br /&gt;
高価なハードウェア上でもっと汎用的にプログラムを動かすために作られたシステムが1964年に作られたIBM S/360です。ここで始めて今日的なオペレーティングシステムが作られます。&lt;br /&gt;
汎用機という言葉は、この「汎用的にプログラムを動かすことができるシステム」という所から来ています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[image:NASAComputerRoom7090.NARA.jpg|left|thumb|300px| 1962年にNASAで使われていた IBM 7090 の写真(NASAサイトより)&amp;lt;ref&amp;gt;NASA の著作権ポリシー http://www.jsc.nasa.gov/policies.html#Guidelines&amp;lt;/ref&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
時代は流れ大型汎用機もダウンサイジングの並に流されます。&lt;br /&gt;
まず最初のダウンサイジングで成功したのはDEC社の科学技術計算用コンピュータPDPシリーズやVAXシリーズです。&lt;br /&gt;
これらはミニコンと呼ばれました。これは1970年代後半から80年代後期まで成功を納めます。&lt;br /&gt;
さらに時代は進み、今度はワークステーションの出現です。&lt;br /&gt;
90年代に入るとDEC社のVAXが、SUN MicrosystemsのSUN ワークステーションに置き換わることになります。&lt;br /&gt;
そのダウンサイジングに大きな役目を果たしたのがUNIXです。&lt;br /&gt;
UNIXはワークステーションからスーパコンピュータまであらゆるサイズのコンピュータ上で使えるようになっていました。&lt;br /&gt;
別の言い方をすれば、ワークステーションからスーパーコンピュータでも十分に満足できる今日的オペレーティングシステムの機能をUNIXは兼ね備えているというわけです。&lt;br /&gt;
しかし、まだ業務や科学技術計算で使うコンピュータと、パーソナルで使うコンピュータには価格的にも性能的にも大きな隔たりがありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代後半になるとIA-32 (&#039;&#039;Intel Architecture,32bit&#039;&#039;)のハードウェアに席捲されます。2000年以降は、ダウンサイジングの到着点です。もう個人で使うパーソナルコンピュータも、業務や科学技術計算で使うものも、ハードウェア的には価格的にも、使われている技術にも、処理能力にも線引きが出来できません。2005年では、64bit CPU、デュアルプロセッサ対応、デュアルコアCPUといった最先端のテクノロジーがコモディティ市場 (一般消費者向け市場) に売られている時代になりました。この傾向はこれから先も続きます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 考えてみよう : ムーアの法則とは限界を示しているのか、いないのか。限界を示しているとしたらなぜなのか。あるいは、ないならばなぜなのか。尚、ムーアの法則の意味は、オリジナルの意味である集積度の向上と、派生的に多く使われている性能の向上のどちらの意味で取ってもよい。&lt;br /&gt;
&lt;br /&gt;
===  2007年現在の状況 ===&lt;br /&gt;
&lt;br /&gt;
下から上がって来た流れと、上から下がってきた流れがぶつかり、しかもそれがうまく融合していない状態が続いていたという状況で、やっと今は、下からの流れを捨てつつ、上からの流れに追いついたといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
下からの流れがいちばん判りやすいのがMicrosoft社のセキュリティの問題です。&lt;br /&gt;
その主力製品であるWindowsは1つはWindows 95/98/Meという流れがあり、もう1つはWindows NT/2000/XPという流れがあります。&lt;br /&gt;
前者は、パーソナルコンピュータの流れ、後者は大型汎用機の流れです。ちなみにWindows NTを設計したのはDEC でVMSの開発をしていて、Microsoft社にヘッドハンティングされたデビット・カトラーです。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上から下がっていたオペレーティングシステムの体系に、下から上がってきたアプリケーション体系を合わせようとしても、なかなかうまくいきません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
パーソナルコンピュータでは、使っているのは一人なわけですから、なんでもオールマイティーにアクセスしても一見問題はないように見えます。一方で大きなコンピュータは一人で使っていては、あまりにも高価なので、多人数で使えるなければなりませんし、そうなれば勝手に他人のファイルや、ましてや勝手にシステムの運用に関わる設定など変えてはいけません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
なんでもアクセスできてしまうパーソナルコンピュータのソフトウェアの方がシンプルかつ簡便な操作を提供できる...と考えても不思議ではありません。&lt;br /&gt;
しかし、便利であったはずの「なんでもアクセスできる」というのがセキュリティの面、特にコンピュータウィルスや脆弱性をついてのシステムへの侵入などクリティカルな問題へ結びつき、それが時代とともに表面化してきました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上からと下からの矛盾が現在のWindowsの根本的な問題となっていました。&lt;br /&gt;
Windows Vista以降では完全にユーザ権限を分離した管理体系による高いセキュリティを持つという能力を提供しています。&lt;br /&gt;
ですが、Windows XP まで動いていたアプリケーションやドライバー類が動かずデベロッパーやユーザが不満を漏らしていたという状況も一方ではありました。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように必要な安全性を達成するには、下から上へ上がってきたようなレガシーなソフトウェアを切り捨てなければ困難です。しかし、一方で膨大なソフトウェア資産があるわけです。この矛盾に終止符を打つのは大変長い時間がかかります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 調べてみよう : 1980年代のスーパーコンピュータやパソコンと呼ばれていたコンピュータの処理能力は、どの程度のものだったのだろうか。その能力の向上はどうだったのだろうか。&lt;br /&gt;
&lt;br /&gt;
== 何をさしてオペレーティングシステムと呼ぶのか ==&lt;br /&gt;
=== 広義と狭義の議論 ===&lt;br /&gt;
&lt;br /&gt;
[[File:Layer-of-System-2.png|thumb|right|400px|System Layer]]&lt;br /&gt;
&lt;br /&gt;
コンピュータ上で動いているソフトウェアのどの部分を指してオペレーティングシステムと呼ぶべきないのか、ということの定義を確認しましょう。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ここでは、一番最下層をハードウェアとして、次にあるのが[[カーネルの構造と機能|カーネルの層]]、その次が汎用に使われるシステムユーティリティの層、そして、特定目的のためにユーザが利用するアプリケーションの層というモデルを考えてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
オペレーティングシステムと、システムユーティリティの両方を1つのまとまりとして、システムソフトウェアと呼びます。「システムを動かすのに最低限必要なソフトウェアセット」という広い意味で捉えたオペレーティングシステムであれば、このシステムソフトウェアがオペレーティングシステムと同意語であると言えます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
しかし「最小限必要な」という定義は、かなり曖昧な表現です。なぜならば、ここには「&#039;&#039;&#039;&#039;&#039;誰が、どのように使うか&#039;&#039;&#039;&#039;&#039;」ということが抜けているからです。&lt;br /&gt;
この部分を拡張していけば、たとえば「ワードブロセッシングを行いたい人が使うためのコンピュータ」という場合は「バンドルされているワードプロセッサのプログラムも含めてオペレーティングシステムである」という奇妙な結論が導かれてしまいます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
この「パッケージを購入した時にバンドルされているアプリケーション群が最小限のセットなので、これがオペレーティングシステムである」という誤解&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
[http://ja.wikipedia.org/w/index.php?title=%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0&amp;amp;oldid=29875236 日本語版wikipedia]ではウェブブラウザや時計などのアクセサリーも広義のオペレーティングシステムだということを書いていますが、そんなことをテストに書いて点数をくれる先生は極めて少数派でしょう。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
は一般には多いようです。&lt;br /&gt;
もしこれが正しいとするならば、これではゲームのソリティアもオペレーティングシステムに含まれることになるので、やはり奇妙な結論と言えます。&lt;br /&gt;
このような表現での「最小パッケージ」とはGNU/Linuxのディストリビューションのデフォルトイントール環境にあたるもので、このオペレーティングシステムの定義を採用するとなると、世の中にはおびただしい数のオペレーティングシステムの種類&amp;lt;ref&amp;gt; オープンソース系オペレーティングシステムののディストリビューションを紹介する https://distrowatch.com  には実に様々なディストリビューションが紹介されています。&amp;lt;/ref&amp;gt;が存在することになります。このような定義を用いると、このような奇妙な結果が導き出されてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では逆に、ここは確実にオペレーティングシステムだろうと言える部分を考えてみます。まずカーネルは当然入ります。ユーザが使うということであれば、&lt;br /&gt;
シェルなども必要です。なぜならシェルがないとコマンドを入力できません。当然ユーザを認証するためのログインに関連するソフトウェアが必要です。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 : カーネルとそれ以外のソフトウェアの切り分けは、実行されるプロセスの実行モードが、どの状態で動いているかで区別します。プロセスの実行モードが、カーネル・モード（UNIX以外のシステムによっては特権モード、スーパーバイザ・モード、あるいはマスタ・モードとも呼ばれる) で動作しているか、ユーザ・モード ( 非特権モード、プロブレム・モード、あるいはスレーブモードとも呼ばれる)で動作しているかどうかです。実行モードに関しては、実行とプロセスに関する話題の時に改めて説明します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
どれくらいのものが最初に用意されるのか、Debian GNU/Linux 6.0を例にして調べてみました。&lt;br /&gt;
&lt;br /&gt;
  ディレクトリ名      コマンド数&lt;br /&gt;
  /bin              95&lt;br /&gt;
  /sbin             110 &lt;br /&gt;
  /usr/bin          452&lt;br /&gt;
  /usr/sbin         107&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; 補足 :  2011年時点で最新のDebian GNU/Linux 6.0 を参考にしています。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このコマンド数も先に述べたようにすべてが必要であるとは限りません。最小限インストールの状態のDebian GNU/Linuxに入っているコマンド数を数えたに過ぎません。&lt;br /&gt;
しかしながら、いくつかのコマンドとそのコマンドで利用されるライブラリ群はオペレーティングシステムには必要になるといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
では、グラフィカルインタフェース(GUI)を提供するためのウィンドウシステムはオペレーティングシステムに入るのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
一般的なUNIXシステムでは、GUIがなくても当然動きますし、サーバシステムではGUIなどは必須ではありません。もちろん先程のDebian GNU/Linux最小限セットの中にはX Window Systemは入っていません。逆にパーソナルコンピュータ用のオペレーティングシステムと呼び販売されているタイプのものではウィンドウシステムは切り離すことができないコンポーネントとなっています。&lt;br /&gt;
&lt;br /&gt;
=== 揺らぐ定義 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Screenshot-Oracle VM VirtualBox.png|thumb|right|450px|コンソールでTOPを実行]]&lt;br /&gt;
&lt;br /&gt;
右図は仮想マシンに&lt;br /&gt;
[https://www.virtualbox.org/ VirtualBox]&lt;br /&gt;
を使い、&lt;br /&gt;
[https://www.debian.org/ Debian GNU/Linux] 6.0&lt;br /&gt;
を最小限インストールし立ち上げてみた状態です。&lt;br /&gt;
もちろんGUIはインストールしていません。なぜならGUIが存在しなくともきちんとコンピュータは動くからです。&lt;br /&gt;
Debian GNU/Linux 6.0 はデスクトップやラップトップ、あるいはサーバに使われるディストリビューションで、組み込み用のものではありません。&lt;br /&gt;
top コマンドを使い、メモリや実行中のプロセスが、どのような状態になっているか観察してみました。&lt;br /&gt;
用意しているメモリは 128MB ですが、この状態で使われている記憶領域は約 26MB しか使っていません。&lt;br /&gt;
df を使ってディスクの利用状況を見てみると、最小のインストールでは約 645MB しか使っていません。&lt;br /&gt;
最小限のセットを考えた場合、このように小さいメモリでも動くことができます。&lt;br /&gt;
この程度の資源でも(英文であれば、ですが）十分にテキストを編集し、スペルをチェックし、フォーマットし、さらにプリンタに出力ができます。&lt;br /&gt;
十分に「パーソナルな」コンピュータだといえます。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
このように使い方によって、あるいはユーザのニーズによって「最小限の」という言葉を使って表現している広義のオペレーティングシステムの意味は揺らぐのがわかるかと思います。&lt;br /&gt;
しかしながら揺らぐからといって無限に定義を拡大していくような問題でもありません。&lt;br /&gt;
そのあたりがグラデーションのようになっていて簡単には線引きないのが特徴だといえるでしょう。&lt;br /&gt;
&lt;br /&gt;
==  コンピュータを仮想化させる == &lt;br /&gt;
[[File:Virtualization.png|thumb|right|450px|Virtualization]]&lt;br /&gt;
我々が、アプリケーションプログラムを使う時、プログラムがコンピュータを占有しているように見えます。ユーザが他にどれだけのプログラムが実行されているかなど気にすることなく使うことができます。&lt;br /&gt;
&lt;br /&gt;
実際は、オペレーティングシステムが、リソースを抽象化し、プログラムに使えるリソースを割り当てることをします。つまり、プログラムは、「仮想化されたコンピュータ」を割り当てられることになります。ユーザに使用許可（パーミッション）が与えられている限り利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
UNIXでは、どのような仮想化の例があるのでしょうか? 典型的な例をいくつかあげて見ましょう。&lt;br /&gt;
&lt;br /&gt;
* CPUのリソースは、プログラムに対し、プロセスという単位で割り当てられます。&lt;br /&gt;
&lt;br /&gt;
* プログラムの使う記憶空間のリソースは、仮想記憶によりコントロールされます。仮想記憶の機構により、主記憶だけではなく、補助記憶装置も使って、主記憶よりも大きい記憶空間を作ることが可能です。その中から、プログラムが必要な大きさの記憶空間リソースを割り当ています。&lt;br /&gt;
&lt;br /&gt;
* 永続的な記憶を保管しておくために、ファイルという抽象的なデータの保管メカニズムを使います。そのファイルを効率的かつ統一的に扱うために、ファイルシステムを作ります。ファイルシステムは、主記憶と補助記憶装置を使って、ファイルのリソースを提供します。&lt;br /&gt;
&lt;br /&gt;
* 入出力装置のリソースのために、デバイスファイルという入出力装置を抽象化した入出力リソースを提供しています。&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
:&#039;&#039;&#039;捕捉&#039;&#039;&#039; さらに&lt;br /&gt;
:[http://www.cl.cam.ac.uk/Research/SRG/netos/xen/ Xen]、[http://www.vmware.com/  VMware]、[https://www.virtualbox.org/ VirtualBox]のようにハードウェア側を抽象化し、1つのハードウェア上に複数のオペレーティングシステムを動かすバーチャルマシンのシステムもあります。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 抽象化の例 ====&lt;br /&gt;
&lt;br /&gt;
UNIXの上で次のコマンドを実行すると端末にHelloと表示されます。これは文字列&amp;quot;Hello&amp;quot;を出力し、その出力先をファイル&lt;br /&gt;
/dev/tty&lt;br /&gt;
への入力するという働きをします。ファイル（デバイスファイルと呼びます）&lt;br /&gt;
/dev/tty&lt;br /&gt;
というのは、自端末を抽象化したものです。&lt;br /&gt;
いくつも端末のウインドウを開いて別々のシェルで行っても、ほかの端末には表示せず、自分の端末のみに出力します。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % echo &amp;quot;Hello&amp;quot; &amp;gt; /dev/tty&lt;br /&gt;
 Hello&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....E、は、オペレーティングシステムから利用可能なリソースを割り当てられ、その中で実行しています。しかし、アプリケーションA、B,....は、割り当てられたリソースのコントロールを意識しません。&lt;br /&gt;
例えば、プログラムがデータを補助記憶装置にファイルの形でデータを残そうとした時、プログラムが、補助記憶装置に使われているハードウェアを直接的にコントロールする必要はありません。つまり、1つのプログラムは、1つの仮想化されたコンピュータで動いているように見えるわけです。&lt;br /&gt;
&lt;br /&gt;
==== 不完全なリソース管理 ====&lt;br /&gt;
&lt;br /&gt;
もし、直接的にコントロールするはずのないリソースをユーザのアプリケーションプログラムがオペレーティングシステムを飛び越して直接的にコントロールできるようなことがあればどうなるのでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
例えば、ユーザのアプリケーションプログラムにバグがあり、割り当てられたリソース以外のリソースを不用意に利用してしまうようなことを許すような不完全なリソース管理のオペレーティングシステムだとどうなるでしょうか？&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
上の図で、プログラムA、B,....は、オペレーティングシステムから割り当てられたリソースを使っているわけですから、オペレーティングシステムの知らない所で、割り当てられていないリソースに勝手なことをされては、一貫性が保てません。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
90年代のパソコンのオペレーティングシステム(と呼ばれていたもの)は、このような不完全なリソース管理の能力しか持っていませんでした。これらはオペレーティングシステムと呼ぶに値するのか非常に疑問で、本来はまだオペレーティングシステムまで発展していない前段階の機能であるハードウェアを監視するモニタと呼ばれるものに分類するのが適切であるように思えます。&lt;br /&gt;
&lt;br /&gt;
==== さらなる仮想化の例 ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===== mmapとファイル =====&lt;br /&gt;
&lt;br /&gt;
例えば、UNIXのmmapと呼ぶ機能です。最近のUNIXは、[http://uc.h2np.net/index.php/%E8%A8%98%E6%86%B6%E7%AE%A1%E7%90%86#mmap mmap]という機能を使ってプログラムは、ファイルを記憶空間に張り付ける (マップする) ことができます。主記憶、補助記憶装置のリソース区別が更に抽象化されプログラムの中で使える記憶空間としてのリソースとなります。もちろん通常のプログラムに割り当てられた記憶領域として、読み込み、書き込みすると、その内容がファイルに反映されます。さらに、ファイルという形で、複数のプロセスから、共有することができます。&lt;br /&gt;
&lt;br /&gt;
===== VFSからデバイスドライバまで =====&lt;br /&gt;
[[File:Filesystem-layer-1.png|thumb|right|400px|File System Layer]]&lt;br /&gt;
[[ファイルシステム]] をさらに抽象化するLinuxのファイルシステムを紹介しましょう。&lt;br /&gt;
ファイルを書き込む説明で「ハードディスクに書き込む」という表現をみたことはないでしょうか。&lt;br /&gt;
目の前にあるパソコン本体のみを考えるならば、このモノに書き出すというので説明は十分なのかも知れませんが、ファイルを書き込む・読み込むというのはもっと抽象的な動作をします。&lt;br /&gt;
&lt;br /&gt;
Linuxのファイルシステムは、上位にVFS (Virtual  File System)が存在し、その下に、FAT、ext4、JFS、XFS、NFS、その他のファイルシステムをもち、さらにその下にバッファキャッシュがあり、さらに下にデバイスドライバがあるといった、何重もの層を重ねる形になっています。&lt;br /&gt;
プログラムは、Linuxのファイルを扱っているだけで、その下がFATのファイルシステムやJFSのファイルシステムであるか、あるいはネットワーク経由でファイルシステムを使うことができるNFSなのかを知らなくても利用することが可能です。&lt;br /&gt;
&lt;br /&gt;
下層には、補助記憶装置との入出力効率を改善するために、バッファキャッシュというクッションをおいてあります。&lt;br /&gt;
さらなる下層には、ハードディスクやフラッシュメモリ (例えばUSBメモリやSDカードなど)といった記憶するためのハードウェア、あるいはNFSのようにネットワークを経由して使うためのネットワークハードウェアをコントロールするためのデバイスドライバの層があります。&lt;br /&gt;
ファイルの情報が最終的にハードディスクに書かれるとしても、ファイルを書き込む動作を行った時点で、まだハードディスクにかかれているわけではありません。&lt;br /&gt;
このようなことにより、たぶん一度や二度は経験したことがあるかも知れませんが、突然、機材の電源を停止すると永続的な情報を保持するためのエリア(ハードディスクやUSBメモリなど)にかかれていなかったファイルの情報は消えてしまうことになります。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;pre class=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
 % sync;sync;sync&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sync&lt;br /&gt;
&amp;lt;ref&amp;gt;&lt;br /&gt;
syncを三回するのは &amp;quot;In the name of the Father, and of the Son, and of the Holy Spirit.(父と子と精霊の御名において)&amp;quot;と唱えて強制的にハードウェアリセットをするためだとむかし誰かに教わった。&lt;br /&gt;
&amp;lt;/ref&amp;gt;&lt;br /&gt;
はバッファキャッシュなどにある情報を含めてすべてデバイスに同期させるコマンド。&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
このように重層的な構造にすることによって、抽象化を図り、かつどの層が変化しようとも、上位の層がその違いを吸収するような形になっています。またこのような枠組みにより柔軟に機能・モジュールを追加、変更することが出来る仕組みになっています。&lt;br /&gt;
&lt;br /&gt;
== 脚注 ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
[[目次]]へ&lt;br /&gt;
&lt;br /&gt;
[[Category:UNIXオペレーティングシステム|1]]&lt;/div&gt;</summary>
		<author><name>Hironobu</name></author>
	</entry>
</feed>