プロセスの概念とその基本操作

Menu Menu


目的

この実験では、Unixの普通のプロセスと軽量プロセス(thread)を用いて、プロセスの概念と基本的な操作である生成と終了について学ぶ。シェル・レベルのコマンドを用いてUNIXのプロセスを観察する。C言語により、プロセスの生成・終了を行うプログラムを作成する。


関連科目

    情報204 オペレーティングシステム   必修、2単位
    教科書: Operating System Concept 


準備

授業のWWWを読んで、プロセスの概念をつかみなさい。プロセスとプログラムの違いは、どこにあるのか。プロセスに関する次のキーワードの意味を調べなさない。

この実験では、普通のプロセス(regular process)と軽量プロセス(lightweight process)という2種類のプロセスを用いる。両者の間に基本的な考え方は共通している。たとえば、状態遷移、スケジューリング、プロセスの切り替え(コンテキストの切り替え)などの考え方や仕組みは、両者で共通である。両者の違いを以下にまとめる。

プロセス軽量プロセス
単位 プログラム手続き(関数)
保護 ありなし
操作 重たい軽い

軽量プロセスは、普通のプロセスの中に作られる小型のプロセスである。普通のプロセスを生成する場合、実行形式が格納されたファイルを指定する。一方、軽量プロセスを生成する場合、手続き(C言語の関数)を指定する。普通のプロセスでは、保護の機能が働き、1つのプロセスが暴走してもシステム全体が停止することはない。一方軽量プロセスでは、一つの軽量プロセスでエラーが発生し実行が続けられなくなると、プロセス全体が以上終了させられる。軽量プロセスの操作(プロセス生成、プロセス間の同期・通信、コンテキスト切り替え)は、普通のプロセスと比較して、10 倍から100倍程高速に行われる。


実験

この実験で用いるプログラムは、/net/open/classes/slab/info1/5-process にある。次のように、各自、自分のホーム・ディレクトリの下にこの実験用のディレクトリを作りなさない。そして、上のディレクトリにあるファイルをコピーしなさない。 ここ にもあります。

    % mkdir ~/実験用ディレクトリ
    % cd ~/実験用ディレクトリ
    % cp -r /net/open/classes/slab/info1/5-process/* .

ここで、「実験用ディレクトリ」には、各自都合の良い名前を付けなさい。他の実験と混ざらないよう、実験テーマごとにディレクトリを作りなさい。そうしなければ、Makefileなどの同じ名前のファイルが上書きされ不都合が起きる可能性がある。


報告書

それぞれの実験に付いて、

    作成したプログラムへのポインタ (file server naha (/net/home/y99/j99xxxx ) 
        にコピーして、その場所を書く)、
    その説明(説明に必要なソースのコピーは最小限にすること)
        (Makefileについても説明すること)、

および、

    その実行結果を付けなさい。

この実験では、プログラムの説明では、フローチャートを付加する必要はない。開発環境と実行環境 (計算機、オペレーティング・システムのバージョン、コンパイラ)を載せなさい。それぞれの実験について、プログラム作成に要した時間を書きなさい。


一般的な注意

報告書は、日本語または英語で記述すること。プログラム、表、図、数式の羅列は、報告書とは認めない。図は必ず本文から参照すること。数学における証明のように、示すべき結論、用いる仮定と前提、推論の詳細について論理的に記述しなさい。


Unixのプロセスの観察と簡単な操作


課題1 コマンドによるプロセスの観察

デスクトップ(pw)またはノートPC(nw)からloginする。2つ以上のウィンドウを開く。一つのウィンドウから ps u コマンドを打ちなさい。

    %pw055 ps u 
    <ps コマンドの出力>

この結果、どのようなプロセスが見えるか。次に、片方のウィンドウで、次のようにcatコマンドを実行する。

    %pw055 cat
    <キーボードからの入力待ち>

もう一つの端末から"ps u"コマンドを打ちなさい。

    %pw055 ps u
    <ps コマンドの出力>

この結果、どのようなプロセスが見えるか。ps コマンドの出力からそれぞれのプロセスの状態、メモリの使用量、プロセスが実行しているプログラムについて説明しなさい。tcsh ( または、あなたのlogin shell)という表示が2行以上見つかるはずである。それより、プロセスとプログラムの違いについて考察しなさい。

nirai, kanai などのSolaris は、System V と呼ばれるOSの種類である。Solaris のps には2種類ある。一つは、/usr/ucb/ps であり、もう一つは/bin/psである。この二つの違いは、ある意味でAT&amp;T System V と(University of California Berkrey) BSD の差を象徴している。時間があったら二つのps の違いについて調べて見よう。


課題2 ps aux コマンドによるプロセスの観察

ps aux コマンドを使って、その計算機で動作している全てのプロセスを調べなさい。何個のプロセスが動作しているか。(niraiとkanai についても調べて見よう) そのうちのいくつかを選んで、どんなプロセスがあるかを説明しなさい。レポートは、ps axu の実行結果のうち、注目すべきものについてのみ抜粋して載せなさい。(ps agx というのも使われるが、この場合はどうか?)

プロセスを見るコマンドには、top というものもある。top の動作を見て、プロセスの生成削除の挙動について観察せよ。


課題3 コマンドによるプロセスの消去

catコマンドから作られたプロセスを、^C により殺しなさい。また、kill コマンドによって殺しなさい。


killコマンドの簡単な使い方

killコマンドは、プロセスに対してシグナルを送るためのコマンドである。シグナルとは、UNIXの用語で、ソフトウェア割り込みを意味する。シグナルを受け取ったプロセスは、何の設定もしてない場合は、終了する。

killコマンドは次のような形式で使われる。

    % kill プロセス番号
    % kill -KILL  プロセス番号

ここで -KILL はシグナルの種類をあらわす。-KILL は、プロセスを必ず終了させるシグナルである。


課題4 コマンドによるプロセスの一時停止

cat コマンドから作られたプロセスを、^Z により一時停止しなさい。また、kill コマンドによって一時停止しなさい。(^Zにより一時停止する時には、誰かがkillコマンドに相当するsignalを出している。いったい誰が出しているのだろう?)そして、tcsh のfgコマンドを使って実行を再開しなさい。

loop.c をコンパイルして動かして、別なウィンドウから、

    kill -STOP プロセス番号
    kill -CONT プロセス番号
    kill -KILL プロセス番号

などとしてみよう。


課題5 ps コマンドの利用法

ps コマンドの次の3つの結果を比較しなさい。
  1. ps
  2. ps u
  3. ps l
表示されるプロセスの違いと、プロセスについての情報の違いについて述べなさい。


課題6 ps コマンドによるプロセスの優先順度の観察

ps alx コマンドを使って、その計算機で動作している全てのプロセスを調べなさい。優先順位の高いプロセスは、どれか。


課題6.5

CPU負荷の高い簡単なプログラムを作成して、それを複数動かし、CPUの温度変化、FANの回転数の変化を観測せよ。

CPUの温度変化、FANの回転数の変化を調べるコマンドを探し、実際の変化を数値で示せ。


課題7 他人のプロセス

killコマンドで他人のプロセスを殺そうとするとどうなるか調べなさい


課題8 その他のsignal

topの中からでもkillコマンドを使用することができる。man signal で表示されるsiganlの役割を実際にsignalを送りながら確認して見よ。


プロセスの生成

次のように、process-create プログラムをコンパイルし、実行してみなさい。

    % make process-create
    % ./process-create
    %

この結果、/usr/bin/calが実行される。そして、1998年5月のカレンダが表示される。

    % ./process-create
	  May 1998
     S  M Tu  W Th  F  S
		    1  2
     3  4  5  6  7  8  9
    10 11 12 13 14 15 16
    17 18 19 20 21 22 23
    24 25 26 27 28 29 30
    31
    %

process-create.c の内容は ここ である。

    main()
    {
    /*
    process_create_l() は、第1引数としてプログラムが格納されているファイ
    ルを指定する。それ以降の引数は、新たに生成されるプロセスに渡される。
    */
	    process_create_l("/usr/bin/cal","cal","5","1998",0 );
    }

process_create_1は、第一引数としてプログラムが格納されているファイルを指定する。それ以降の引数は、新たに生成されるプロセスに引き渡される引数である。

    process_create_l( file,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9 )
	char *file,*a0,*a1,*a2,*a3,*a4,*a5,*a6,*a7,*a8,*a9 ;
    {
	int child_pid ;
	    if( (child_pid=fork()) == 0 )
	    {
		char *argv[11] ;
		argv[0] = a0 ;
		argv[1] = a1 ;
		argv[2] = a2 ;
		argv[3] = a3 ;
		argv[4] = a4 ;
		argv[5] = a5 ;
		argv[6] = a6 ;
		argv[7] = a7 ;
		argv[8] = a8 ;
		argv[9] = a9 ;
		argv[10] = 0 ;
		execve( file, argv, environ );
		perror( file );
		exit( 1 );
	    }
	    else
	    {
		return( child_pid );
	    }
    }

この課題では、 UNIX では、プログラムからプロセスを生成するため、fork()とexecve()という二つのシステム・コールを使うことに注意しなさい。fork()は、プロセスのコピーを行うシステム・コール、execve()は、実行しているプログラムを切り替えるシステム・コールである。


課題8 実行形式プログラムからのプロセス生成

プログラムprocess-create.cを書き換えて、cal以外のプログラムから2つのプロセスを作るプログラムを作りなさない。ここでは、プロセスを生成するために使うプログラムとしては、次のようなキーボードからの入力を行わないものを選びなさい。
  1. ls -l
  2. who
  3. finger user
  4. cat filename
自分で作ったプログラムを使う時には、キーボード(標準入力)からの入力を行わないものを使いなさない。 ( 入力を行うものを使うと、どうなるのだろう? 課題9 のwait を使うと、入力を行うコマンドでも、ちゃんと動作するようになる。これは何故だろうか? )

UNIXのシェルは、利用者から受け取った文字列から、実行すべきプログラムを探し、引数を整えて、プロセスを生成する。シェルがプロセスを生成する時には、内部的には、process_create_1()と似た仕掛けを利用している。

process_create_l()やその内部で利用しているexecvc()システム・コールは、実行形式が格納されているファイルの絶対パス名、またはcurrent working directory からの相対パス名を必要とする。すなわち、実行形式が格納されているファイル名がスラッシュ(/)から始まる場合は絶対パス名として、ドット(.)から始まる場合は、相対パス名として解釈される。

シェルは、環境変数PATH(tcshのシェル変数pathと連動している)に含まれているディレクトリにあるコマンドを検索し実行する機能がある。この時、どのような仕掛けを利用しているかを考察しなさい。(tcshのrehashコマンドとも関係があるので、tcshのドキュメントを調べて見よう)

ここで「キーボードからの入力を行わないプログラム」というのは、シェルから実行した時に、キーボードを打たなくても自動的に終了するようなものである。自動的に終了しない、「キーボードからの入力を行うプログラム」の例としては、emacs, less, mnews がある。このようなキーボードからの入力を受け付けて動くようなプログラムを、「対話的なプログラム」という。(正確には、cat なども入力を受け付けるが、これは emacs などとは少し状況が違う。キーボードの入力を即時にしようするか、一旦、バッファにためて使用するかという差がある。)


課題9 wait()システム・コールの利用

process-create は、入力を必要とするようなコマンドでは問題がある。また、次のように表示が乱れることがある。

    % ./process-create
    %      May 1998
     S  M Tu  W Th  F  S
		    1  2
     3  4  5  6  7  8  9
    10 11 12 13 14 15 16
    17 18 19 20 21 22 23
    24 25 26 27 28 29 30
    31

この図のように、シェルのプロンプト(%)の後に、calコマンドの結果が表示されている。この理由は、process-createが、子供のcalプロセスの終了をまたずに終了しているからである。この問題を、wait()システム・コールを用いて解決しなさい。( man 2 wait とすると英語のマニュアルを読むことができる)

ある対話的なプログラムのプロセスの中から別の対話的なプログラムのプロセスを起動しようとすると、元のプロセスと新しいプロセスの間でキーボードから来るデータの奪い合いが生じる。このキーボードからのデータを、どのプロセスに送ったら良いかを管理するしかけは、UNIXでは、suspend などと同様にジョブ制御機能の一部である。tcsh は、& を付けないで実行されたコマンドのプロセスに対してキーボードからの入力を送るように設定する。

tcshのfgは、キーボードからの入力を指定されたプロセスに送るようにし、指定されたプロセスをsuspend状態からactiveな状態へ変更するコマンドである。

元のプロセスと新しいプロセスの間でキーボードから来るデータの奪い合いを調停する方法の一つは、子供のプロセスが動いている間、元のプロセスを停止させることである。これを実現するには課題9で用いるwait()システム・コールを使えば良い。この仕掛けは、mnews などで記事を書く時にエディタ(mule/emacs)を実行する時に使われている。


課題10 process_create_l()関数の改良

process-create.c のprocess_create_1()は、最大10個までしか引数を取ることができない。この制限を、stdarg マクロを用いて緩和しなさい。例えば、1000個まで受け付けられるように書き換えなさない。( 実際には、Unix kernel でこの上限は決まっている。これは、どこで決まっているのだろうか?)

もちろん、man stdarg を使うこと。


課題11 Java によるプロセス生成

以下は、Java を使ったプロセス生成である。processExample.Create

    package processExample;
    import java.io.*;
    public class Create {
	    static final int BUFSIZE = 4096;
	    static public void main(String [] args) throws IOException {
		    Process p = new ProcessBuilder("/usr/bin/cal", "5","2006").start();
		    InputStream out = p.getInputStream();
		    byte[] buf = new byte[BUFSIZE];
		    int length;
		    while((length=out.read(buf))>0) {
			    System.out.write(buf,0,length);
		    }
	    }
    }

(Java 1.4 以前では、ProcessBuilder ではなくて、Runtime.getRuntime() を使う)

課題8, 9 に相当する修正を行い、実行を確認せよ。確認は、Junit 4 を使って下さい。

while文中の操作がが必要な理由を、Java API document の記述を指摘して示せ。


Shinji KONO / Tue Nov 25 13:48:09 2008