System V のセマフォー API を使用して POSIX のセマフォー API を実装する

System V のセマフォー API を使用して、POSIX API の標準プラットフォーム以外にもセマフォーのサポートを拡張する

「POSIX API を使用する必要があるものの、開発プラットフォーム (z/OS など) が POSIX API をサポートしていない」ということはないでしょうか?あきらめることはありません。System V のセマフォー API を使用して POSIX のセマフォー API を実装することで、皆さんが作成したコードをより多くのプラットフォームで使用できるようにし、そのコードを保守できる状態に保つ方法を学びましょう。

Suchitra Venugopal, Senior System Analyst, IBM

Photo of Suchitra VenugopalSuchitra Venugopal はソフトウェア業界に合計10 年の経験があり、主にオープンシステム技術を扱ってきました。彼女は IBM Optim を HP Itanium プラットフォームにポーティングした経験や SPSS を z/OS プラットフォームにポーティングした経験もあり、現在は Platform Technology Centre に勤務しています。彼女は developerWorks の記事「デバッグ用フォーマット、DWARF と STAB」を共同執筆しました。



Shikha Maheshwari, System Software Engineer, IBM

Photo of Shikha MaheshwariShikha Maheshwari は 2006年に IBM インドのソフトウェア研究所に入社し、それ以来 Platform Technology Centre に所属しています。彼女は IBM のブランド全体にわたり、またいくつかのプラットフォームにわたってポーティング、テスト、開発のプロジェクトに従事してきました。彼女が扱った製品には、TxSeries、TSIEM、TEM、ISW、SPSS、Cognos、WBM があります。



Adarsh Thampan, Development Manager, IBM

Photo of Adarsh ThampanAdarsh Thampan は C/C++ 技術で構築された IBM 製品を HP Itanium に、また System Z や z/OS で実行する Linux にポーティングする業務に従事してきました。彼はホワイトペーパー「Mixed Platform Stack Project: Linux on System z and IBM z/OS」を共同執筆しました (http://www-03.ibm.com/support/techdocs/atsmastr.nsf/WebIndex/WP101522)。また、developerWorks の記事「デバッグ用フォーマット、DWARF と STAB」も共同執筆しました。



2012年 11月 15日

概要

z/OS プラットフォームにコードを移植する場合に直面する大きな問題は、POSIX のセマフォー API が z/OS 上では利用できないことです。通常、Linux/UNIX/Windows プラットフォーム上で実行されるプログラムの大部分はPOSIX のセマフォーを使用して開発されています。

この問題を解決する 1 つの方法として、POSIX API を使用する代わりに z/OS 向けの System V の API の実装を使用する方法があります。しかしこの方法は、全体にわたる大幅なコードの変更が必要になり、その実装をコーディングしてテストする大量の作業が必要になります。それよりも優れた方法として、System V の API を使用して z/OS に POSIX API を実装する方法があります。この方法では、移植のためのコード変更が最小限ですみます。これらのコード変更はアプリケーション・コードとは分離され、別のセマフォー・ヘッダー・ファイルおよび C ファイルとして含められます。このヘッダー・ファイルと C ファイルは、任意のプラットフォームで使用することができる汎用的なものです。

この記事では、System V のセマフォー API を使用して POSIX のセマフォー API を実装する方法について説明します。

POSIX API を使用する必要がありながら開発プラットフォームが System V の API 以外をサポートしていない場合 (z/OS など)、この記事は非常に役に立つはずです。またこの記事では、開発の観点から POSIX のセマフォーと System V のセマフォーとを有意に区別します。

POSIX のセマフォーと System V のセマフォーを比較する

セマフォーには、POSIX のセマフォーと System V のセマフォーという 2 つのタイプがあります。

セマフォーは個々のユニットとして扱うことも、あるセットの中の要素として扱うこともできます。System V の IPC セマフォーは大規模な配列の場合もあるため、極めて重たくなっています。1 つのセマフォー・セットは 1 つの制御構造と個々のセマフォーの配列で構成されます。1 つのセマフォー・セットは最大 25 個の要素を含むことができます。System V の IPC セマフォー関数には、semget()semop()semctl() があります。

  • semget()semget() システム・コールにより、新しいセマフォー・セットを作成することや、既存のセマフォー・セットにアクセスすることができます。
  • semop() ― セマフォー操作を実行します。
  • semctl() ― セマフォー作成者は、この関数を使用してセマフォーの所有権やアクセス権を変更することができます。

POSIX のセマフォーは System V のセマフォーよりもはるかに軽量です。POSIX のセマフォー構造体では、複数のセマフォーからなる配列ではなく、1 つのセマフォーを定義します。POSIX のセマフォー関数には以下に記載するものがあります。

  • sem_open() ― 名前付きセマフォーに接続します。オプションで名前付きセマフォーを作成することができます。
  • sem_init() ― セマフォー構造体を初期化します (呼び出し元プログラムの内部で行われるため、名前付きセマフォーではありません)。
  • sem_close() ― 開いた状態のセマフォーへの接続を終了します。
  • sem_unlink() ― 開いた状態のセマフォーへの接続を終了し、最後のプロセスがセマフォーを閉じると、そのセマフォーを削除します。
  • sem_destroy() ― セマフォー構造体を破棄します。
  • sem_getvalue() ― セマフォーの値を指定された整数にコピーします。
  • sem_wait()sem_trywait() ― どちらもセマフォーの値をデクリメント (セマフォーをロック) しますが、セマフォーが他のプロセスによって保持されていてロックできない場合、前者は関数呼び出しの処理をブロックし、後者はブロックせずにエラーを返してリターンします。
  • sem_post() ― セマフォーのカウントをインクリメントします。

POSIX には、セマフォーの作成、初期化、操作のための単純な処理が用意されています。これにより、プロセス間の通信を効率的に処理することができます。System V のセマフォーは、単一のステップで複数のインクリメント/デクリメントを行うアトミック操作を実装する必要がある場合にはメリットがあります。それ以外の場合には POSIX のセマフォーを使用してください。


z/OS 上でのセマフォーの制約

z/OS は System V のセマフォーのみをサポートし、POSIX のセマフォーはサポートしていません。

z/OS では、どの POSIX API も使用することはできません。z/OS で使用できる System V のセマフォー API は、semop()semget()semctl() の 3 つのみです。z/OS でセマフォー API を使用する必要がある場合は、System V の API のみを使用することになります。

表 1. プラットフォームによるセマフォーのサポート状況
LinuxAIX®zLinuxHPSolarisMac OSz/OS
POSIXyesyesyesyesyesyesno
System Vyesyesyesyesyesyesyes

System V のセマフォー API を使用して POSIX のセマフォー API を実装する

POSIX のセマフォー関数とセマフォー・タイプはすべて、semaphore.h でプロトタイプ宣言されています (つまり定義されています)。z/OS などの特定のレガシー・プラットフォームでは、System V のセマフォー関数以外は使用できません。そのため、z/OS には (POSIX のセマフォー関数を定義するための) semaphore.h はありません。System V のセマフォー関数は sys/sem.h でプロトタイプ宣言されています。

このセクションでは、System V のセマフォー API を使用して POSIX のセマフォー API を実装する方法について説明します。この方法は z/OS と AIX で実装され、POSIX のセマフォーを使用して十分にテストされています。

Semaphore_zOS.h と Semaphore_zOS.c には、POSIX の API を使用して z/OS における System V のセマフォー API を実装してあります。私達が実装した関数は以下のとおりです。

int sem_init(int *semid,int pshared,unsigned int value)

この関数を実装するには、System V のセマフォー API の semget と semctl を使用します (リスト 1)。semget() 関数と semctl() 関数どちらの場合も、返されるエラー・コードは POSIX での実装と同じです。

リスト 1. sem_init 関数の実装
int sem_init(int *sem,int pshared,unsigned int value)
{
    // get the semaphore first
	semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666);
	if(semid== -1)
    /*assign err code and return*/
	else
     int ret = semctl(*semid,0,SETVAL,value);  // initialize the semaphore
	if(ret == -1)
      /* assign errcode for semctl and return */
	  return ret;
}

int sem_destroy(int *semid)

リスト 2semctl() 関数を使用して sem_destroy を実装する方法を示します。

リスト 2. sem_destroy 関数の実装
int ret = semctl(*semid,0,IPC_RMID);

指定されたセマフォー・セットを削除するには IPC_RMID を使用します。

int sem_wait(int *semid)

この関数はセマフォーをロックします。リスト 3 にこの関数を semop() を使用して実装する方法を示します。

リスト 3. sem_wait 関数の実装
        sb.sem_num=0;
        sb.sem_op=-1; //Allocate resources
        sb.sem_flg=0;
        if (semop(*semid, sb, 1) == -1)

int sem_trywait(int *semid)

この関数もセマフォーをロックし、semop() を使用して実装します。実装は sem_flg=IPC_NOWAIT となっている点を除けば sem_wait と同様です。リスト 4 を見てください。

リスト 4. sem_trywait 関数の実装
        sb.sem_num=0;
        sb.sem_op=-1; //Allocate resources
        sb.sem_flg= IPC_NOWAIT;
        if (semop(*semid, sb, 1) == -1)

この関数は、セマフォーが現在ロック可能な場合のみ、そのセマフォーをロックします。sem_wait 関数はセマフォーがロックされるまで待ちますが、sem_trywait は待ちません。sem_trywait は単純に現在ロック可能かどうかのみをチェックし、ロック可能でない場合は単純にリターンします。

int sem_post(int *semid)

この関数は semop() を使用してセマフォーのロックを解除します。リスト 5 を見てください。

リスト 5. sem_post 関数の実装
        sb.sem_num=0;
        sb.sem_op=1;  // Release resources.
        sb.sem_flg=0;
        if (semop(*semid, sb, 1) == -1)

sem_open()sem_close()sem_unlink()sem_getvalue() といった他の POSIX API は必要がなかったため、まだ実装されていません。これらも上記と同じようにして実装することができます。

これらの実装に対してエラー・コードを設定する場合は、他のプラットフォームにおける POSIX の実装のエラー・コードを調べてください。


テスト・アプリケーション

123 のフロー・チャートは、セマフォー API をテストするために作成された単純なテスト・アプリケーションを示しています。(図 1、2、3 は実際には 1 つのフロー・チャートですが、フォーマットの関係で分割してあります。)。このテスト・アプリケーションは System V のセマフォーを使用して実装されています。このテスト・アプリケーションはスレッドの配列を作成し、sem_init()sem_post()sem_destroy()sem_wait()sem_trywait() など、POSIX のセマフォー API を使用しています。

図 1. テスト・アプリケーションのフロー・チャート (その 1)
テスト・アプリケーションのフロー・チャート (その 1) を示す図
図 2. テスト・アプリケーションのフロー・チャート (その 2)
テスト・アプリケーションのフロー・チャート (その 2) を示す図
図 3. テスト・アプリケーションのフロー・チャート (その 3)
テスト・アプリケーションのフロー・チャート (その 3) を示す図

クリックして大きなイメージを見る

図 3. テスト・アプリケーションのフロー・チャート (その 3)

テスト・アプリケーションのフロー・チャート (その 1、その 2、その 3) を示す図

ケース 1 ― POSIX のセマフォー API を使用した場合と、System V のセマフォー API を使用して実装した POSIX API を使用した場合とを AIX で比較テストする

このセクションではテスト・アプリケーションを実行した結果を示します。1 つは既存の POSIX セマフォー API を使用した場合の結果、もう 1 つは System V の API を使用して実装した POSIX API を使用した場合の結果であり、どちらも AIX プラットフォーム上で実行されています。セマフォーを取得するスレッドの順序はまちまちですが、これはその順序がプラットフォームと優先順位に依存するためです。

両方のテスト・アプリケーションの実行結果がまったく同じであれば、System V の API を使用して実装した POSIX API は適切に動作する、と結論付けることができます

リスト 6 に System V のセマフォー API を使用して実装した POSIX API を使用したテスト・アプリケーションの出力を示します。

リスト 6. System V のセマフォー API を使用して実装した POSIX API を使用したテスト・アプリケーションの出力
bash-3.2# ./test1posiximpln
Thread no 0 id = 258 created
Threadid  id =258(ThreadFunction1), locked and incrementing the count  
Count (ThreadFunction1) = 1
Thread no 1 id = 515 created
Thread no 2 id = 772 created
Thread no 3 id = 1029 created
Thread id 1029 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread no 4 id = 1286 created
Thread no 5 id = 1543 created
Thread no 6 id = 1800 created
Thread id 1800 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread no 7 id = 2057 created
Thread no 8 id = 2314 created
Thread no 9 id = 2571 created
Thread id 2571 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread 258 going to release lock
Thread id = 515(ThreadFunction2) , locked and incrementing the count   
Count (ThreadFunction2) = 2
Thread id 515 going to release lock
Thread id = 772(ThreadFunction2) , locked and incrementing the count   
Count (ThreadFunction2) = 3
Thread id 772 going to release lock
Thread id = 1286(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 4
Thread id 1286 going to release lock
Thread id = 1543(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 5
Thread id 1543 going to release lock
Thread id = 2057(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 6
Thread id 2057 going to release lock
Thread id = 2314(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 7
Thread id 2314 going to release lock
All threads joined, Final count = 7
bash-3.2#

リスト 7 に既存の POSIX API を使用したテスト・アプリケーションの出力を示します。

リスト 7. 既存の POSIX API を使用したテスト・アプリケーションの出力
bash-3.2# ./test1original

Thread no 0 id = 258 created
Threadid  id =258(ThreadFunction1), locked and incrementing the count  
Count (ThreadFunction1) = 1
Thread no 1 id = 515 created
Thread no 2 id = 772 created
Thread no 3 id = 1029 created
Thread no 4 id = 1286 created
Thread id 1029 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread no 5 id = 1543 created
Thread no 6 id = 1800 created
Thread id 1800 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread no 7 id = 2057 created
Thread no 8 id = 2314 created
Thread no 9 id = 2571 created
Thread id 2571 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread 258 going to release lock
Thread id = 515(ThreadFunction2) , locked and incrementing the count   
Count (ThreadFunction2) = 2
Thread id 515 going to release lock
Thread id = 772(ThreadFunction2) , locked and incrementing the count   
Count (ThreadFunction2) = 3
Thread id 772 going to release lock
Thread id = 1286(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 4
Thread id 1286 going to release lock
Thread id = 1543(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 5
Thread id 1543 going to release lock
Thread id = 2057(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 6
Thread id 2057 going to release lock
Thread id = 2314(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 7
Thread id 2314 going to release lock
All threads joined, Final count = 7
bash-3.2#

どちらの場合もテスト・アプリケーションは AIX 上で同じ結果を出力しています。

ケース 2 ― System V を使用して実装したセマフォー API を使用して z/OS でアプリケーションをテストする

私達は System V のセマフォーを使用して実装したセマフォー・ファイルを作成し、同じテスト・アプリケーションを使用して z/OS でテストしました。また、AIX でも既存の POSIX API を使用した別のテスト・アプリケーションを実行し、出力を比較しました。

z/OS でのテストの結果と AIX でのテストの結果が同じであれば、System V のセマフォー API を使用して実装した POSIX セマフォーは適切に動作する、と結論付けることができます。

リスト 8 に、(AIX の場合と) 同じテスト・アプリケーション・プログラムを z/OS で実行した場合の出力を示します。

リスト 8. System V のセマフォー API を使用した場合のテスト・アプリケーションの出力
STLAB60:../finalCode:> ./test1sys5

Thread no 0 id = 542160384 created
Threadid  id =542160384(ThreadFunction1), locked and incrementing the count
Thread no 1 id = 542195200 created      Count (ThreadFunction1) = 1
Thread no 2 id = 542199552 created
Thread no 3 id = 542203904 created
Thread no 4 id = 542208256 created
Thread no 5 id = 542212608 created
Thread no 6 id = 542216960 created
Thread no 7 id = 542221312 created
Thread no 8 id = 542225664 created
Thread no 9 id = 542230016 created
Thread id 542216960 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread id 542230016 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread id 542203904 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread 542160384 going to release lock
Thread id = 542195200(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 2
Thread id 542195200 going to release lock
Thread id = 542199552(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 3
Thread id 542199552 going to release lock
Thread id = 542221312(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 4
Thread id 542221312 going to release lock
Thread id = 542225664(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 5
Thread id 542225664 going to release lock
Thread id = 542208256(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 6
Thread id 542208256 going to release lock
Thread id = 542212608(ThreadFunction2) , locked and incrementing the count     
Count (ThreadFunction2) = 7
Thread id 542212608 going to release lock
All threads joined, Final count = 7

リスト 9 に既存の POSIX API を使用して AIX でテスト・アプリケーションを実行した場合の出力を示します。

リスト 9. 既存の POSIX API を使用した場合のテスト・アプリケーションの出力
bash-3.2# ./test1original

Thread no 0 id = 258 created
Threadid  id =258(ThreadFunction1), locked and incrementing the count  
Count (ThreadFunction1) = 1
Thread no 1 id = 515 created
Thread no 2 id = 772 created
Thread no 3 id = 1029 created
Thread no 4 id = 1286 created
Thread id 1029 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread no 5 id = 1543 created
Thread no 6 id = 1800 created
Thread id 1800 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread no 7 id = 2057 created
Thread no 8 id = 2314 created
Thread no 9 id = 2571 created
Thread id 2571 is in ThreadFunction1, semaphore is already locked and not waiting. 
Hence will not increment the counter
Thread 258 going to release lock
Thread id = 515(ThreadFunction2) , locked and incrementing the count   
Count (ThreadFunction2) = 2
Thread id 515 going to release lock
Thread id = 772(ThreadFunction2) , locked and incrementing the count   
Count (ThreadFunction2) = 3
Thread id 772 going to release lock
Thread id = 1286(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 4
Thread id 1286 going to release lock
Thread id = 1543(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 5
Thread id 1543 going to release lock
Thread id = 2057(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 6
Thread id 2057 going to release lock
Thread id = 2314(ThreadFunction2) , locked and incrementing the count  
Count (ThreadFunction2) = 7
Thread id 2314 going to release lock
All threads joined, Final count = 7
bash-3.2#

これらの結果から、テスト・アプリケーションの動作は z/OS と AIX とで同じであることがわかります。


まとめ

z/OS などのレガシー・プラットフォームで POSIX のセマフォー API を使用するには、semaphore.h ファイルと semaphore.c ファイルをダウンロードし、これらのファイルを使用して POSIX API を呼び出します。私達はこのコード・フラグメントのテストに成功し、このコード・フラグメントが適切であることを証明しました。


ダウンロード

内容ファイル名サイズ
Semaphore test applicationssemaphore_testapplns.zip16KB

参考文献

学ぶために

製品や技術を入手するために

  • IBM ソフトウェアの試用版にアクセスし (ダウンロードまたは DVD で入手することができます)、特に開発者のために用意されたソフトウェアを利用して皆さんの次のオープンソース開発プロジェクトを革新してください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux, Open source, Java technology
ArticleID=845105
ArticleTitle=System V のセマフォー API を使用して POSIX のセマフォー API を実装する
publish-date=11152012