情報学類 分散システム 2008年12月02日
筑波大学システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2008/2008-12-02
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/

図? メインフレームと端末
利用者は地理的に分散(distributed)しているが、プログラムは、すべて中央の1台のコン ピュータで動作する。文字端末の役目
「端末」は、メインフレーム(ホスト)と文字回線で接続されている。 電話回線等を使ったモデムによる接続。2400bps-9600bps。 IBMのものは、半二重。

図? 集中型システムのハードウェアとOS
ハードウェアやオペレーティング・システムの働きで、次のようなことが(あ る程度のレベルで簡単に)実現できる。
Process1()
{
write(file1,buf,bytes);
...
...
}
|
Process2()
{
...
...
read(file1,buf,bytes);
}
|
Process3()
{
...
...
read(file1,buf,bytes);
}
|

図? 共有メモリ型マルチプロセッサ(バス共有)

図? LANに接続されたPC
遠隔のメモリは、アクセスできない(no remote memory access)。 機種が違うこともある。| 交通機関 | ネットワーク |
|---|---|
| 徒歩 4km/h | 64kbps 電話回線 |
| 自動車 40km/h | 640kbps ADSL(低速) |
| 飛行機 800km/h | イーサネット(10Mbps), ADSL(中速), 無線LAN |
| 人工衛星(第一宇宙速度) 28440km/h | 450Mbps, イーサネット(100Mbps-10Gbps) |
最後の性質が大事である。
構成要素の数が増えた時にどうなるか。 10台で動くものが100台、1000台で動くか。
実用になり、かつ、利益に見合うコストで実現できる範囲を探すことが大事になる。

図? 単一のコンピュータでハイスコアをファイルに保存
ライブラリの機能int get_highscore(score_record_t records[], int len)
score_record_t型)を最大 len 個だけ取得する。
実際に保存していた数を返す。
int put_score(int score, char *user)
.」を忘れないように。
% mkdir hiscore-c
% cd hiscore-c
% cp ~yas/dsys/highscore/centralized/highscore.h .
% cp ~yas/dsys/highscore/centralized/highscore.c .
% cp ~yas/dsys/highscore/centralized/add-hiscore.c .
% cp ~yas/dsys/highscore/centralized/show-hiscore.c .
% cp ~yas/dsys/highscore/centralized/Makefile .
% ls
Makefile add-hiscore.c highscore.c highscore.h show-hiscore.c
% make
cc -g -c -o add-hiscore.o add-hiscore.c
cc -g -c -o highscore.o highscore.c
cc -g add-hiscore.o highscore.o -o add-hiscore
cc -g -c -o show-hiscore.o show-hiscore.c
cc -g show-hiscore.o highscore.o -o show-hiscore
% ls
Makefile add-hiscore.c highscore.c highscore.o show-hiscore.c
add-hiscore add-hiscore.o highscore.h show-hiscore show-hiscore.o
%
make コマンドを実行すると、Makefile の記述に従い2つの実行
形式のファイル add-hiscore と add-hiscore が作られる。
例題を実行するには、環境変数 hiscoredata にファイル名を
設定する。その方法は、make help で表示される。
% make help
setenv hiscoredata `mktemp /tmp/coins-dsys-XXXXXXXXXX`
ls -l $hiscoredata
./add-hiscore score name
./show-hiscore num
rm $hiscoredata
%
help に従い、/tmp の下に予測が困難なファイル名でデータファイルを
作成する。(ホーム・ディスクの下に作成した場合は、うまく動作しない。理由
は後述。)
mktemp コマンドを実行し、その出力で、
環境変数 hiscoredataを設定する。
% setenv hiscoredata `mktemp /tmp/coins-dsys-XXXXXXXXXX`
% printenv hiscoredata
/tmp/coins-dsys-8ofae8kMu4
% echo $hiscoredata
/tmp/coins-dsys-8ofae8kMu4
% ls -l $hiscoredata
-rw------- 1 yas wheel 0 Nov 30 20:10 /tmp/coins-dsys-8ofae8kMu4
%
この例では、mktemp コマンドは、
/tmp/coins-dsys-8ofae8kMu4 というファイルを
作成し、そのファイル名を標準出力に出力する。
実験が終了したら rm コマンドで削除すること。
バッククォート(` `は、シェルの文法で、
コマンドの出力をコマンド行に持ってくる。上の例では、以下のコマンドと同
じである。
% setenv hiscoredata /tmp/coins-dsys-8ofae8kMu4
環境変数は、csh の組み込みコマンド printenv で表示できる。
シェルでは、$ をつけて参照することもできる。
プログラムの中では、getenv() ライブラリ関数で参照できる。
環境変数 hiscoredata を設定した後は、add-hiscore コマンド
と show-hiscore を実行することができる。
% ./add-hiscore 10 "Yasushi Shinjo"
% ls -l $hiscoredata
-rw------- 1 yas wheel 32 Nov 30 20:11 /tmp/coins-dsys-8ofae8kMu4
% ./show-hiscore 10
10 Yasushi Shinjo
% ./add-hiscore 20 "Kazuhiko Kato"
% ./show-hiscore 10
20 Kazuhiko Kato
10 Yasushi Shinjo
% ls -l $hiscoredata
-rw------- 1 yas wheel 64 Nov 30 20:24 /tmp/coins-dsys-8ofae8kMu4
%
実験が終了したら、rm コマンドで削除する。
% ls -l $hiscoredata
-rw------- 1 yas wheel 64 Nov 30 20:24 /tmp/coins-dsys-8ofae8kMu4
% rm $hiscoredata
%
get_highscore() 関数を呼び出す簡単なプログラム。
[show-hiscore.c]
1:
2: /*
3: show-hiscore.c -- The main function for get_highscore().
4: Created on: 2008/11/28 18:40:56
5: ~yas/dsys/highscore/centralized/show-hiscore.c
6: */
7:
8: #include <stdio.h> /* stderr, fprintf() */
9: #include <stdlib.h> /* strtol() */
10: #include "highscore.h"
11:
12: static void show_score( int top );
13:
14: static void usage( char *comname ) {
15: fprintf(stderr,"Usage: %% %s n\n", comname);
16: exit( 1 );
17: }
18:
19: main( int argc, char *argv[], char *envp[] ) {
20: int top;
21: char *name ;
22: if( argc != 2 )
23: usage( argv[0] );
24: top = strtol( argv[1], 0, 10);
25: show_score( top );
26: }
27:
28: static void show_score( int top ) {
29: score_record_t records[HIGHSCORE_MAX_RECORDS];
30: int n, i ;
31: if( top > HIGHSCORE_MAX_RECORDS ) {
32: fprintf(stderr,"Warning: top too large: %d\n",top);
33: top = HIGHSCORE_MAX_RECORDS;
34: }
35: n = get_highscore( records, top );
36: for( i=0; i<n; i++ ) {
37: printf("%10d %s\n", records[i].score, records[i].name );
38: }
39: }
get_highscore()関数を呼び出す。
put_score() 関数を呼び出す簡単なプログラム。
[add-hiscore.c]
1:
2: /*
3: add-hiscore.c -- The main function of put_score().
4: Created on: 2008/11/28 17:22:21
5: ~yas/dsys/highscore/centralized/add-hiscore.c
6: */
7:
8: #include <stdio.h> /* stderr, fprintf() */
9: #include <stdlib.h> /* strtol() */
10: #include "highscore.h"
11:
12: void usage( char *comname ) {
13: fprintf(stderr,"Usage: %% %s score \"User Name\"\n", comname);
14: exit( 1 );
15: }
16:
17: main( int argc, char *argv[], char *envp[] ) {
18: int score ;
19: char *name ;
20: if( argc != 3 )
21: usage( argv[0] );
22: score = strtol( argv[1], 0, 10);
23: name = argv[2];
24: put_score( score, name );
25: }
put_score()関数を呼び出す。
1:
2: /*
3: highscore.h -- Hiscore Library for centralized systems.
4: Created on: 2008/11/28 11:49:18
5: ~yas/dsys/highscore/centralized/highscore.h
6: */
7:
8: #ifndef _HIGHSCORE_LIB_CENTRALIZED_H_
9: #define _HIGHSCORE_LIB_CENTRALIZED_H_
10:
11: #define HIGHSCORE_MAX_RECORDS 10
12: #define HIGHSCORE_NAME_LEN 28
13: #define HIGHSCORE_FILE_ENV "hiscoredata"
14:
15: struct score_record {
16: int score;
17: char name[HIGHSCORE_NAME_LEN];
18: };
19: typedef struct score_record score_record_t;
20:
21: extern int get_highscore(score_record_t records[], int len);
22: extern put_score(int score, char *user);
23:
24: #endif _HIGHSCORE_LIB_CENTRALIZED_H_
score_record_tで表現する。
この構造体は、全体で32バイトある。の最初の4バイトは、整数型で、得点、残
りの28バイトは、文字の配列。ASCII で最大27文字まで保存できる。文字が含
まれない部分は、0が入る。
score_record_t 型の配列で表す。
hiscoredata に設定する。
1: 2: /* 3: highscore-lib-centralized.c -- Hiscore Library for centralized systems. 4: Created on: 2008/11/28 11:45:58 5: ~yas/dsys/highscore/centralized/highscore-lib-centralized.c 6: */ 7: 8: #include <fcntl.h> /* open() */ 9: #include <sys/types.h> /* fstat() */ 10: #include <sys/stat.h> /* fstat() */ 11: #include <string.h> /* memcpy(), memset() */ 12: #include <stdio.h> /* snprintf(), perror() */ 13: #include <stdlib.h> /* getenv() */ 14: #include <sys/file.h> 15: 16: #include "highscore.h" 17: 18: static int insert_score( score_record_t records[], int len, int nelement, 19: int score, char *user ); 20: static int find_posision( score_record_t records[], int len, int nelement, 21: int score ); 22:
23: int get_highscore(score_record_t records[], int len) {
24: int fd;
25: struct stat stat;
26: ssize_t bytes;
27: char *filename;
28:
29: if( (filename=getenv(HIGHSCORE_FILE_ENV)) == NULL ) {
30: fprintf(stdout,"No environment: %s\n",HIGHSCORE_FILE_ENV );
31: return( 0 );
32: }
33: if( (fd = open(filename,O_RDONLY)) < 0 ) {
34: perror( filename );
35: return( 0 );
36: }
37: if( flock(fd,LOCK_SH) < 0 ) {
38: perror("flock");
39: goto error0;
40: }
41: if( fstat(fd,&stat) < 0 ) {
42: perror("fstat");
43: goto error1;
44: }
45: bytes = (stat.st_size <= len*sizeof(score_record_t)) ?
46: stat.st_size : len*sizeof(score_record_t) ;
47: if( read(fd, records, bytes)!=bytes ) {
48: perror("read");
49: goto error1;
50: }
51: if( flock(fd,LOCK_UN) < 0 ) {
52: perror("flock");
53: goto error0;
54: }
55: close( fd );
56: return( bytes/sizeof(score_record_t) );
57:
58: error1: flock( fd,LOCK_UN );
59: error0: close( fd );
60: return( 0 );
61: }
62:
hiscoredata (HIGHSCORE_FILE_ENV) から
ファイル名を取得する。
O_RDONLY で開く。
LOCK_SH)でロックする。
fstat() で調べる。
LOCK_SH (shared lock または read lock)
LOCK_EX (exclusive lock または write lock)

図? 普通のロックと読み書きロック
注意: 最近では、flock() ではなくて、fcntl() を使うのが一般的。 fcntl() では、ファイルの一部をロックできる。
63: int put_score(int score, char *user) {
64: int fd, n;
65: struct stat stat;
66: ssize_t bytes;
67: off_t offset ;
68: score_record_t records[HIGHSCORE_MAX_RECORDS];
69: char *filename;
70:
71: if( (filename=getenv(HIGHSCORE_FILE_ENV)) == NULL ) {
72: fprintf(stdout,"No environment: %s\n",HIGHSCORE_FILE_ENV );
73: return( 0 );
74: }
75: if( (fd = open( filename,O_RDWR|O_CREAT, 0666)) < 0 ) {
76: perror( filename );
77: return( 0 );
78: }
79: if( flock(fd,LOCK_EX) < 0 ) {
80: perror("flock");
81: goto error0;
82: }
83: if( fstat(fd,&stat) < 0 ) {
84: perror("fstat");
85: goto error1;
86: }
87: bytes = (stat.st_size <= HIGHSCORE_MAX_RECORDS*sizeof(score_record_t))?
88: stat.st_size : HIGHSCORE_MAX_RECORDS*sizeof(score_record_t) ;
89: if( read(fd, records, bytes)!=bytes ) {
90: perror("read");
91: goto error1;
92: }
93:
94: n = insert_score( records,HIGHSCORE_MAX_RECORDS,bytes/sizeof(score_record_t),
95: score, user );
96:
97: if( n > 0 ) {
98: offset = 0L;
99: if( lseek( fd, offset, SEEK_SET )< 0 ) {
100: perror("lseek");
101: goto error1;
102: }
103: bytes = n * sizeof(score_record_t);
104: if( write(fd, records, bytes)!=bytes ) {
105: perror("write");
106: goto error1;
107: }
108: }
109:
110: if( flock(fd,LOCK_UN) < 0 ) {
111: perror("flock");
112: goto error1;
113: }
114: close( fd );
115: return( 1 );
116:
117: error1: flock( fd,LOCK_UN );
118: error0: close( fd );
119: return( 0 );
120: }
121:
hiscoredata (HIGHSCORE_FILE_ENV) から
ファイル名を取得する。
O_RDWR (read-write) で開く。
LOCK_EX)でロックする。
fstat() で調べる。
insert_score())。
122: static int insert_score( score_record_t records[], int len, int nelement,
123: int score, char *user ) {
...
140: static int find_posision( score_record_t records[], int len, int nelement,
141: int score ) {
...
insert_score() は、スコアの配列に、要素を追加する。先頭が一
番高得点になるようにソートして入れる。空きがない場合には、一番小さなス
コアの場所をつぶす。
find_posision() は、ソートされた配列でどの場所に要素を挿入
すればよいかを探す。
[Makefile]
注意:r系コマンドは、ネットワーク上を生パスワードが流れて危険なので、使われない。 その代わりに、ssh, slogin, scp が使われる。
現在、広く使われているオペレーティング・システムで、 ネットワーク通信機能があるものは、これに分類される。

図? ネットワークOSでのアプリケーションの実行
目標
分散OSの種類

図? 分散OSでのアプリケーションの実行
種類

図? ミドルウェアを用いた分散アプリケーションの実行
どこまで隠せば分散型プログラミング言語と呼んでもよいか? 「socket があれば、分散型プログラミング言語」とは、定義したくない。 永続言語との比較。