Document

セマフォのシステムコールと応用プログラム
セマフォのシステムコールと応用プログラム







semget(): セマフォを生成し、識別子を得る
semctl(): セマフォの制御
semop(): セマフォの操作
ipcs - IPC リソース情報の表示
ipcrm – IPCの各資源(メッセージキュー・セマフォ・共有メモリ)を削除
する
事例: セマフォの応用プログラム writer & cleaner
事例: fork()したプロセス間の排他制御
セマフォのシステムコールと応用プログラム
semget(): セマフォを生成し、識別子を得る
インクルードファイル
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
書式
int semget(key_t key, int
nsems, int semflg);
戻値
成功時 セマフォ識別子、
失敗時 -1
使用例)
int semid;
key_t semkey;
semkey=ftok("seminit", 'a');
semid=semget(semkey, 1, IPC_CREAT|0666);



key: セマフォの鍵
nsems: セマフォの総数
semflg:
 IPC_CREAT|0666
セマフォのシステムコールと応用プログラム
semctl(): セマフォの制御
インクルードファイル
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
書式
int semctl(int semid, int
semnum, int cmd, …);
戻値
成功時 0 、
失敗時 -1
使用例)
int semid;
semctl(semid, 0, SETVAL, 1);



semid: セマフォ識別子
semnum: セマフォ番号
cmdの種類
 GETVAL:セマフォ値を得る
 SETVAL: セマフォ値をセット
 IPC_RMID:セマフォを削除
 IPC_STAT:セマフォ状態を得る
 IPC_SET:semid_ds構造体の値を
セット
セマフォのシステムコールと応用プログラム
semop(): セマフォの操作
ロック操作
インクルードファイル
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
書式
int semop(int semid, struct
sembuf *sops, unsigned int
nsops);
戻値
成功時 0 、
失敗時 -1
使用例)
int semid;
struct sembuf buf[1];
buf[0].sem_num=0;
buf[0].sem_flg=0;
buf[0].sem_op = -1;
semop(semid,buf,1);



アンロック操作
使用例)
int semid;
struct sembuf buf[1];
buf[0].sem_num=0;
buf[0].sem_flg=0;
buf[0].sem_op = 1;
semop(semid,buf,1);
semid: セマフォ識別子
セマフォ番号
struct sembuf {
unsigned short int sem_num
short int sem_op;
セマフォ値を
short int sem_flg;
増す(減す)値
}
nsops: 操作するセマフォの総数
セマフォのシステムコールと応用プログラム
ipcs - IPC リソース情報の表示
ipcs は、IPC リソース機能に関する情報を出力する。

-i を指定すると、後続の id で指定されたリソースの情報だけが出力
される。
リソースの指定は次のようになる:

-m シェアードメモリセグメントを指定する。

-q メッセージキューを指定する。

-s セマフォを指定する。

-a すべてのリソースの情報が出力される(ディフォルト)。
出力フォーマットの指定は、次のようになる:

-t リソースが最後に変更された時間を出力する。

-p リソースの所有、作成、最終変更を示すプロセスIDを出力する。

-c リソースの作成ユーザーおよびグループの情報を出力する。

-l 各リソースの上限値を出力する。

-u 各リソースの使用状況を示すサマリが出力される.
セマフォのシステムコールと応用プログラム
ipcrm – IPCの各資源(メッセージキュー・
セマフォ集合・共有メモリ ID)を削除する

ipcrm は System V プロセス間通信 (interprocess communication, IPC) オブジェクトと、
それに関連するデータ構造をシステムから削除する。









これらのオブジェクトを削除するためには、スーパーユーザーであるか、オブジェクト
の作成者または所有者でなければならない。
メッセージキューオブジェクトとセマフォオブジェクトの削除は、 (他のプロセスがその
オブジェクトの IPC 識別子を持っていたとしても) 即座に行われる。
共有メモリオブジェクトが削除されるのは、現在付加 (attach) されている全てのプロ
セスが (shmdt(2) で) 仮想アドレス空間からオブジェクトを分離 (detach) してからで
ある。
-M shmkey
を削除する。
-m shmid
を削除する。
-Q msgkey
-q msgid
-S semkey
-s semid
最後の分離が行われた後、 shmkey で作成された共有メモリセグメント
最後の分離が行われた後、 shmid で識別される共有メモリセグメント
msgkey で作成されたメッセージキューを削除する。
msgid で識別されるメッセージキューを削除する。
semkey で作成されたセマフォを削除する。
semid で識別されるセマフォを削除する。
セマフォのシステムコールと応用プログラム
事例: セマフォの応用プログラムwriter & cleaner (1)
writer.c(画面に数字を書く)


セマフォ識別子を獲得
以下を繰返す

セマフォをロックする

画面に数字(0~4)を書く

セマフォをアンロックする
cleaner.c(画面の数字を消す)


セマフォ識別子を獲得
以下を繰返す

セマフォをロックする

カーソルを後退し数字を消す

セマフォをアンロックする
seminit.c
int main() {
int semid;
key_t semkey;
semkey=ftok("seminit", 'a');
semid=semget(semkey, 1,
IPC_CREAT|0666);
semctl(semid, 0, SETVAL, 1);
return EXIT_SUCCESS;
}
各プロセスは、同じ
鍵を持っている
writer
使い終わったら1増や
す(アンロック)
writer
使う時
1減らす
(ロック)
-1
writer使用中
Critical
Section
+1
セマフォ
セマフォ
セマフォ
セマフォ
セマフォ
1
0
0
1
0
-1
初期値=1
cleaner
使う時1減らす
(ロック)
cleaner使用中
Critical
待ち解除 Section
セマフォのシステムコールと応用プログラム
事例: セマフォの応用プログラムwriter & cleaner (2)
writer.c(画面に数字を書く)
cleaner.c(画面の数字を消す)
int main() {
int semid;
key_t semkey;
struct sembuf buf[1];
int main() {
int semid;
key_t semkey;
struct sembuf buf[1];
キーを作る
semkey=ftok("seminit", 'a');
semid=semget(semkey, 1, IPC_CREAT|0666);
buf[0].sem_num=0;
buf[0].sem_flg=0;
セマフォ識別子を得る
while (1) {
int i;
ロック操作
buf[0].sem_op = -1;
semop(semid,buf,1);
for (i=0; i<5; i++) {
printf("%d",i);
資源
リソース
fflush(stdout);
(ディスプレイ)
sleep(1);
を独占的に使う
}
buf[0].sem_op = 1;
semop(semid,buf,1);
sleep(1);
アンロック操作
}
return EXIT_FAILURE;
キーを作る
srand(time(NULL));
semkey=ftok("seminit", 'a');
semid=semget(semkey, 1, IPC_CREAT|0666);
buf[0].sem_num=0;
buf[0].sem_flg=0;
ロック操作
while (1) {
int i, loop;
buf[0].sem_op = -1;
semop(semid,buf,1);
乱数を5で割った余+1
loop=rand()%5+1;
for (i=0; i<loop; i++) {
printf("\b \b");
後退し、空白を
fflush(stdout);
書き、後退する
sleep(1);
}
buf[0].sem_op = 1;
semop(semid,buf,1);
sleep(1);
}
アンロック操作
return EXIT_FAILURE;
}
}
セマフォのシステムコールと応用プログラム
事例: fork()したプロセス間の排他制御
•
•
•
•
セマフォの初期化プロセスを作成する。
初期化プロセスで作成したセマフォと同
一の鍵を利用して、独立した複数のプ
ロセス間で、排他処理を行う。
各プロセスは、自身のpidを出力する。
各プロセスは、ディスプレイの利用をク
リティカルセクションとして保護し、排他
制御する。
セマフォの生成・初期化・削除を管
理するプログラム
independent_sem_init.c
kishima@DdeDynabook-4 $ gcc
independent_sem_init.c -o independent_sem_init
kishima@DdeDynabook-4
$ ./independent_sem_init
$ Enterが押されたらセマフォを削除します
kishima@DdeDynabook-4 $
independent_sem_init.cにより作成された
セマフォを使って排他処理を行うプロセス
(キーが同じならば複数起動させても排他処
理が行われます)
independent_sem_ope.c
kishima@DdeDynabook-4 $ gcc
independent_sem_ope.c -o independent_sem_ope
kishima@DdeDynabook-4 $ ./independent_sem_ope &
[1] 3892
kishima@DdeDynabook-4 $ ./independent_sem_ope &
[2] 2384
kishima@DdeDynabook-4 $ ./independent_sem_ope &
[3] 3076
kishima@DdeDynabook-4 $ pid=3892, pid=3892,
pid=3892, pid=3892, pid=3892, pid=3892, pid=3892,
pid=3892, pid=3892, pid=3892, pid=2384, pid=2384,
pid=2384, pid=2384, pid=2384, pid=2384, pid=2384,
pid=2384, pid=2384, pid=2384, pid=3076, pid=3076,
pid=3076, pid=3076, pid=3076, pid=3076, pid=3076,
pid=3076, pid=3076, pid=3076,
[1] Done
./independent_sem_ope
[2]- Done
./independent_sem_ope
[3]+ Done
./independent_sem_ope
kishima@DdeDynabook-4 $