コンピューター:C言語講座:セマフォについて
概要
プロセス間通信をいろいろ取り上げ、共有メモリを説明したからにはIPC関連を制覇しようかと考え、セマフォを使ってみました。
セマフォとは遮断機の意味で、共有のリソースを複数のプロセスが同時にアクセスするのを防ぐのに使用されます。IPCのセマフォを使わなくてもopen()システムコールの特性を利用してファイルを使用してセマフォを実現することも可能ですし、lockf(),flock()などでもファイルのロックは可能です。
IPCのセマフォを使用するメリットは共有メモリと同様に一箇所のデータだけで管理するので高速な点と、セマフォのシステム自身にロックの管理機能が備わっている点ではないかと思います。
サンプル
セマフォは説明を読んでも難解で、実際に使ってみたほうが少しはわかると思いますので、サンプルをまず示してみます。
サンプルのプログラムを複数起動し、それぞれでロックしたり、アンロックしたりして動きを見てください。
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int sem_get(path)
char *path;
{
int sid;
union semun{
int val;
struct semid_ds *buf;
ushort *array;
}c_arg;
if((sid=semget(ftok(path,0),1,0666|IPC_CREAT))== -1){
perror("semget");
return(-1);
}
if(semctl(sid,0,GETVAL,c_arg)==0){
c_arg.val=1;
if(semctl(sid,0,SETVAL,c_arg)==-1){
perror("semctl");
return(-1);
}
}
return(sid);
}
int sem_lock(sid)
int sid;
{
struct sembuf sb;
sb.sem_num=0;
sb.sem_op=-1;
sb.sem_flg=0;
if(semop(sid,&sb,1)== -1){
perror("semop");
return(-1);
}
return(1);
}
int sem_unlock(sid)
int sid;
{
struct sembuf sb;
sb.sem_num=0;
sb.sem_op=1;
sb.sem_flg=0;
if(semop(sid,&sb,1)== -1){
perror("semop");
return(-1);
}
return(1);
}
void main()
{
int sid,ret;
char buf[128];
union semun{
int val;
struct semid_ds *buf;
ushort *array;
}c_arg;
setbuf(stdout,NULL);
if((sid=sem_get("/tmp/aaa"))==-1){
exit(-1);
}
printf("sid=%d\n",sid);
while(1){
ret=semctl(sid,0,GETVAL,c_arg);
printf("<%d> [L]ock / [U]nlock : ",ret);
gets(buf);
if(tolower(buf[0])=='l'){
ret=sem_lock(sid);
printf("sem_lock()=%d\n",ret);
}
else if(tolower(buf[0])=='u'){
ret=sem_unlock(sid);
printf("sem_unlock()=%d\n",ret);
}
}
}
サンプルでは/tmp/aaaというファイルをキーにセマフォを行なっていますが、実際はftok()で単なる整数のキーにしてから使用します。semget()でセマフォを獲得し、IDを得ます。semctl()にSETVALを指定してサンプルではセマフォの値を1にセットしています。semop()で実際にロック、アンロックを行ないますが、opに負の値を指定するとロックの動作になり、セマフォの値から指定した値を引いて行き、値が0の時にロックしようとすると待ちになります。opに正の値を指定すると、セマフォの値に加えられ、もし他のプロセスがロックしようとして待ちになっている場合にセマフォの値が0より大きくなるとロックが実行されるようになります。
セマフォの値はsemctl()にGETVALを指定して得られます。
このように、セマフォの値を使用して排他処理を実現する為の情報を与えてくれるのがセマフォです。
ただ、私にはよく理解が出来ない点も多く、参考にした書籍でもあまり明確な説明がありませんでした。個人的には共有メモリを用いて自分でセマフォを実現したほうが応用がきいて良いように思います。どなたかセマフォならでは、という例がありましたら教えてください。
なお、共有メモリと同様に不要のセマフォはsemctl()にIPC_RMIDを指定して削除するか、ipcrmコマンドで削除する必要があります。