POSIX Semaphore
- POSIXセマフォには、名前付きのセマフォと名前なしのセマフォがある。
- 名前付きセマフォの操作関数は次のとおり。
- sem_open (名前付きでセマフォを作成)
- sem_wait (セマフォに対してP操作)
- sem_post (セマフォに対してV操作)
- sem_close (セマフォを閉じる)
- sem_unlink (セマフォをシステムから削除)
- 名前付きセマフォは、sem_openで作成する。 このとき、/dev/shm下にはsem.(セマフォの名前)という名前のファイルが作成される。
- 名前付きセマフォの作成に際して、sem_openの引数modeを設定することにより、名前付きセマフォに対する書き込み/読み込みのアクセス許可を設定することができる(すでに作成されるセマフォにアクセスするには、セマフォへの書き込み/読み込みの両方が許可されている必要がある)。
- 名前付きセマフォは、バージョン2.6以降のカーネルで使用可能(それより前のバージョンでは、名前なしのセマフォのみサポートされている)。
- 名前付きセマフォの名前は、/で始まる必要がある。
- sem_getvalueを使用すると、現在のセマフォのカウントを取得することができる。
- sem_trywaitを使用すると、セマフォのカウンタが0になっていても実行がブロックされず、即座に復帰する(このとき、errnoにはEAGAINが設定される)。 カウンタが1以上の場合は、sem_waitと同等の動きとなる。
- 名前なしのセマフォの場合は、sem_open/sem_closeの代わりにsem_init/sem_destroyを使用する。
- 名前なしのセマフォの場合はカーネルでは管理しないため、使用しなくなってもsem_unlinkはコールしない。
- POSIXセマフォ以外にも、SystemVセマフォが存在する
使用例
// gcc -pthread -std=c99
#include <stdio.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
// セマフォに与える名前
#define SEMAPHORE_NAME ("/interproc_semaphore_sample")
// 生成する子プロセス数
#define CHILD_MAX (10)
// セマフォオブジェクト
sem_t* semaphore = NULL;
//
// ミリ秒単位のsleep
//
int msleep( int milliseconds )
{
struct timespec t;
t.tv_sec = milliseconds / 1000;
t.tv_nsec = ( milliseconds % 1000 ) * 1000000;
return nanosleep( &t, NULL );
}
//
// 子プロセスの処理
//
void child_main()
{
pid_t pid = getpid();
int semval = 0;
printf( "ProcessID %d, started\n", pid );
// セマフォのカウンタを表示する
sem_getvalue( semaphore, &semval );
printf( "->semaphore count: %d\n", semval );
printf( "ProcessID %d, wait for semaphore\n", pid );
// セマフォに入る
sem_wait( semaphore );
printf( "ProcessID %d, access to semaphore\n", pid );
// 適当な時間だけ待ち合わせる
msleep( 1500 );
printf( "ProcessID %d, release semaphore\n", pid );
// セマフォを出る
sem_post( semaphore );
// セマフォのカウンタを表示する
sem_getvalue( semaphore, &semval );
printf( "->semaphore count: %d\n", semval );
printf( "ProcessID %d, exited\n", pid );
}
//
// 親プロセス
//
int main( void )
{
// 初期値3のセマフォを作成する
// (すでに同名のセマフォが存在する場合は、modeとvalueは無視される)
semaphore = sem_open( SEMAPHORE_NAME, O_CREAT | O_EXCL, 0777, 3 );
printf( "semaphore created\n" );
// 250ミリ秒おきに子プロセスを生成する
for ( int count = 0; count < CHILD_MAX; count++ )
{
pid_t pid = fork();
if ( 0 == pid )
{
// 子プロセスの処理を開始する
child_main();
_exit( 0 );
}
else if ( -1 == pid )
{
printf( "fork failed\n" );
return 1;
}
msleep( 300 );
}
// すべての子プロセスの終了を待機する
for ( int count = 0; count < CHILD_MAX; )
{
int status;
pid_t pid;
pid = waitpid( -1, &status, WNOHANG );
if( 0 < pid )
{
// 子プロセスが終了した
count++;
continue;
}
else if ( -1 == pid )
{
break;
}
// 500ミリ秒おきに子プロセスの状態を監視する
msleep( 500 );
}
printf( "all processes are finished\n" );
// セマフォを破棄する
sem_close( semaphore );
printf( "semaphore closed\n" );
// セマフォを削除する
sem_unlink( SEMAPHORE_NAME );
printf( "semaphore unlinked\n" );
return 0;
}
実行例
semaphore created ProcessID 7862, started ->semaphore count: 3 ProcessID 7862, wait for semaphore ProcessID 7862, access to semaphore ProcessID 7863, started ->semaphore count: 2 ProcessID 7863, wait for semaphore ProcessID 7863, access to semaphore ProcessID 7864, started ->semaphore count: 1 ProcessID 7864, wait for semaphore ProcessID 7864, access to semaphore ProcessID 7865, started ->semaphore count: 0 ProcessID 7865, wait for semaphore ProcessID 7866, started ->semaphore count: 0 ProcessID 7866, wait for semaphore ProcessID 7862, release semaphore ProcessID 7865, access to semaphore ->semaphore count: 0 ProcessID 7862, exited ProcessID 7867, started ->semaphore count: 0 ProcessID 7867, wait for semaphore ProcessID 7863, release semaphore ->semaphore count: 1 ProcessID 7863, exited ProcessID 7866, access to semaphore ProcessID 7868, started ->semaphore count: 0 ProcessID 7868, wait for semaphore ProcessID 7864, release semaphore ->semaphore count: 1 ProcessID 7864, exited ProcessID 7867, access to semaphore ProcessID 7869, started ->semaphore count: 0 ProcessID 7869, wait for semaphore ProcessID 7870, started ->semaphore count: 0 ProcessID 7870, wait for semaphore ProcessID 7871, started ->semaphore count: 0 ProcessID 7871, wait for semaphore ProcessID 7865, release semaphore ->semaphore count: 1 ProcessID 7865, exited ProcessID 7868, access to semaphore ProcessID 7866, release semaphore ->semaphore count: 1 ProcessID 7866, exited ProcessID 7869, access to semaphore ProcessID 7867, release semaphore ->semaphore count: 1 ProcessID 7867, exited ProcessID 7870, access to semaphore ProcessID 7868, release semaphore ->semaphore count: 1 ProcessID 7868, exited ProcessID 7871, access to semaphore ProcessID 7869, release semaphore ->semaphore count: 1 ProcessID 7869, exited ProcessID 7870, release semaphore ->semaphore count: 2 ProcessID 7870, exited ProcessID 7871, release semaphore ->semaphore count: 3 ProcessID 7871, exited all processes are finished semaphore closed semaphore unlinked