ソフト開発塾

KONDO-NETサーチ(KLSH)
- 新着 - VB - VC - Perl - PHP - カテゴリに登録 -

Linux

Perlでの排他制御 その4


排他制御を行う方法で、よく出てくるのが、「セマフォ」である。
Perlでは、semget semctl semop によって行うようである。
まず、cat /proc/sysvipc/sem で、キーを確認しておきましょう。

Perlでは、semget semctl semop を、使用するのだが、それぞれについて説明(解説)をわかる範囲で行う。(間違っている場合あるかも)
semget
[書式] semget KEY,NSEMS,FLAGS
[説明]
 System V IPC 関数 semget を呼び出します。  セマフォID か、エラー時には未定義値を返します。
[解説]
FLAGS に IPC_CREAT が指定されていて、 KEY に対応するセマフォ集合が存在しない場合、 NSEMS 個のセマフォからなる新しい集合が作成される。 FLAGS に IPC_CREAT と IPC_EXCL の両方が指定された場合、 KEY に対応するセマフォ集合が既に存在すると、 semget() は失敗する。
セマフォ集合の作成を行わない場合は、引き数 NSEMS に (don't care を意味する) 0 を指定できる。 そうでない場合は、 NSEMS は 0 より大きい値でなければならず、セマフォ集合あたりのセマフォの最大数 (SEMMSL) 以下でなければならない。
IPC_CREAT = 512 IPC_EXCL = 1024
実際の初期化 例
sub SEMINIT {
	my ($KEY)=@_;

	$SEMID = semget($KEY, 10, 03600);
	if (defined($SEMID)) {
		print "SEMID = $SEMID\n";
		$RC = semctl($SEMID, 0, &SETVAL, 1);
		if (! defined($RC)) {
			die "SETVAL failure $!\n";
		}
	} else {
		print "semget create failed $!\n";
		$SEMID = semget($KEY, 0, 0);
		if (defined($SEMID)) {
			print "Exsiting SEMID = $SEMID\n";
		} else {
			die "semget failed2 $!\n";
		}
	}
	return $SEMID;
}

semctl
[書式] semctl ID,SEMNUM,CMD,ARG
[説明]
 CMD が、&IPC_STAT か &GETALL のときには、ARG は、返される semid_ds 構造体か、セマフォ値の配列を納める変数でなければなりません。  ioctl と同じように、エラー時には未定義値、ゼロのときは "0 but true"、それ以外なら、その値そのものを返します。
[解説]
semctl() は、 ID で指定されたセマフォ集合 (semaphore set) またはセマフォ集合の SEMNUM 番目のセマフォに対して、 CMD で指定された制御操作を行なう (集合内のセマフォの番号は 0 から始まる)。
CMD について
IPC_STAT
semid に関連づけられたカーネルデータ構造体の情報を arg.buf で指された semid_ds 構造体へコピーする。 semnum 引き数は無視される。呼び出したプロセスはそのセマフォ集合に対する読み込み許可を持たなければならない。
IPC_SET
arg.buf で指定された semid_ds 構造体のメンバーのいくつかの値を、このセマフォに関連づけられたカーネルデータ構造体に書き込み、 sem_ctime メンバーの値も更新する。構造体の以下のメンバーが更新される: sem_perm.uid, sem_perm.gid, sem_perm.mode (の最下位 9 ビット)。呼び出したプロセスの実効 UID が所有者 (sem_perm.uid) または作成者 (sem_perm.cuid) と一致するか、呼び出した人が特権を持たなければならない。 semnum 引き数は無視される。
IPC_RMID
セマフォ集合をただちに削除し、その集合上の semop() コールでブロックされている全てのプロセスを目覚めさせる (エラー値が返されて、 errno に EIDRM が設定される)。呼び出したプロセスの実効ユーザ ID がそのセマフォ集合の作成者または所有者と一致するか、呼び出した人が特権を持たなければならない。 semnum 引き数は無視される。
IPC_INFO (Linux 固有)
システム全体でのセマフォの制限とパラメータに関する情報を、 arg.__buf が指す構造体に入れて返す。この構造体は seminfo 型である。 seminfo は _GNU_SOURCE 機能検査マクロが定義された場合に で以下のように定義される:
SEM_INFO (Linux 固有)
IPC_INFO のときと同じ情報を格納した seminfo 構造体を返す。但し、以下のフィールドにはセマフォが消費しているシステム資源に関する情報が格納される点が異なる。 semusz フィールドは現在システム上に存在するセマフォ集合の数を返す。 semaem フィールドはシステム上の全てのセマフォ集合に含まれるセマフォの総数を返す。
SEM_STAT (Linux 固有)
IPC_STAT と同じく semid_ds 構造体を返す。但し、 semid 引き数は、セマフォ識別子ではなく、システム上の全てのセマフォ集合に関する情報を管理するカーネルの内部配列へのインデックスである。
GETALL
集合の全てのセマフォの semval の値 (現在の値) を arg.array に返す。 semnum 引き数は無視される。呼び出したプロセスはそのセマフォ集合に読み込み許可を持たなければならない。
GETNCNT
システムコールは集合の semnum 番目のセマフォの semncnt の値 (このセマフォの値が増加するのを待っているプロセス数) を返す (集合の semnum 番目のセマフォの semval の増加を待っているプロセスの数を返す)。呼び出したプロセスはそのセマフォ集合に読み込み許可を持たなければならない。
GETPID
システムコールは集合の semnum 番目のセマフォの sempid の値 (集合の semnum 番目のセマフォに最後に semop() コールを実行したプロセスの PID) を返す。呼び出したプロセスはそのセマフォ集合に読み込み許可を持たなければならない。
GETVAL
システムコールは集合の semnum 番目のセマフォの semval の値を返す。呼び出したプロセスはそのセマフォ集合に読み込み許可を持たなければならない。
GETZCNT
システムコールは集合の semnum 番目のセマフォの semzcnt の値 (このセマフォの値が 0 になるのを待っているプロセスの数) を返す (集合の semnum 番目のセマフォの semval の値が 0 になるのを待っているプロセスの数を返す)。呼び出したプロセスはそのセマフォ集合に読み込み許可を持たなければならない。
SETALL
集合の全てのセマフォの semval に arg.array で指定された値を設定する。その集合に関連する semid_ds 構造体の sem_ctime メンバーの値も更新する。全てのプロセスのセマフォの変更についてのアンドゥ・エントリ (semop(2) を参照) は消去 (clear) される。セマフォの値の変更により、他のプロセス内でブロックされている semop() コールの続行が許可されると、それらのプロセスは起こされる (wake up)。 semnum 引き数は無視される。呼び出したプロセスはそのセマフォ集合に変更 (書き込み) 許可を持たなければならない。
SETVAL
集合の semnum 番目のセマフォの semval に arg.val の値を設定する。その集合に関連する semid_ds 構造体の sem_ctime メンバーの値も更新する。全てのプロセスのセマフォの変更についてのアンドゥ・エントリは消去される。セマフォの値の変更により、他のプロセス内でブロックされている semop() コールの続行が許可されると、それらのプロセスは起こされる (wake up)。呼び出したプロセスはそのセマフォ集合に変更 (書き込み) 許可を持たなければならない。
使用例 削除処理
sub SEMEXIT {
	my ($SEMID)=@_;
	$ret = semctl($SEMID, 0, 0, 0);
	if (! $ret) {
		die "セマフォの削除失敗: $!\n";
	}
}
使用例 GETNCNT
	$ncount = semctl($SEMID, 0, 14,0);
	if (! defined($ncount)) {
		die "GETNCNT failure $!\n";
	}
	print "GETNCNT = [$ncount]\n";
IPC_STAT = 2 IPC_SET = 1 IPC_RMID = 0 IPC_INFO = GETVAL = 12 GETALL = 13 GETNCNT = 14 GETZCNT = 15

semop
[書式] semop KEY,OPSTRING
[説明]
 シグナルを送信や、待ち合わせなどのセマフォ操作を行なうために、System V IPC 関数 semop を呼び出します。 OPSTRING は、semop 構造体の pack された配列でなければなりません。  semop 構造体は、それぞれ、pack("sss", $sem_num, $sem_op, $sem_flag) のように作ることができます。  セマフォ操作の数は、OPSTRING の長さからわかります。  成功時には真を、エラー時には偽を返します。  例として、
    $semop = pack("sss", $sem_num, -1, 0);
    die "Semaphore trouble: $!\n" unless semop($semid, $semop);
は、セマフォ ID $semid のセマフォ $sem_num で待ち合わせを行ないます。  セマフォにシグナルを送るには、"-1"を "1" に変更してください。
[解説]
pack("sss", $sem_num, $sem_op, $sem_flag) $sem_op には、通常 0 , 1,-1 を、使用します。 $sem_flag には IPC_NOWAIT と SEM_UNDO が設定できる。 SEM_UNDO が指定された操作は、そのプロセスが終了した時に自動的に取り消される。
sem_op が正の整数の場合、操作としてその値をセマフォの値 (semval) に加える。 さらにこの操作に SEM_UNDO が指定されている場合は、システムはこのセマフォの プロセス・アンドゥ数 (semadj) を更新する。 この操作は必ず実行でき、プロセスの停止は起こらない。呼び出し元プロセスは対象のセマフォ集合を変更する許可がなければならない。
sem_op が 0 の場合、プロセスにはそのセマフォ集合に対する読み込み許可がなければならない。 これは「ゼロまで待つ」動作である。 semval が 0 ならば、操作は直ちに行われる。 semval が 0 でない場合、 sem_flag に IPC_NOWAIT が指定されていれば、 semop() は失敗する。
sem_op が 0 未満の場合、プロセスにはそのセマフォ集合を変更する許可がなければならない。 semval が sem_op の絶対値以上の場合は、操作は直ちに実行される: semval から sem_op の絶対値が減算される。 さらに、この操作に SEM_UNDO が指定されている場合は、このセマフォのプロセス・アンドゥ数 (semadj) を更新する。 semval が sem_op の絶対値より小さく、 sem_flag に IPC_NOWAIT が指定された場合は、 semop() は失敗する。
IPC_NOWAIT = 2048 SEM_UNDO = 4096

簡単な使用例

	&SEMINIT(1234);

	$OP = pack("sss", 0, -1, 0);
	semop($SEMID, $OP) || die "semop failre";

	open IN, '<','累計金額' or die "オープン失敗 $!";
	$sum = ;
	close IN;

	$sum += 100;

	open OUT, '>','累計金額' or die "オープン失敗 $!";
	print OUT $sum;
	close OUT;

	$OP = pack("sss", 0, 1, 0);
	semop($SEMID, $OP) || die "semop failre";

ソフト開発塾 ソフト開発塾(LINUX)
---KONDO-NET.GR.JP---