ここは旧式の4DドキュメントWebサイトです。最新のアップデートされたドキュメントを読むには新サイトをご利用下さい→ developer.4d.com

ホーム

 
4D v20.6
セマフォーとシグナル

セマフォーとシグナル  


 

概要  

セマフォーとシグナルは、どちらも4D ランゲージによって提供される、マルチプロセスアプリケーションでのプロセス間でのやり取りを管理し衝突を避けるためのツールです。それぞれ目的と用途が異なります:

  • セマフォーとは、2つまたはそれ以上のプロセスが同じリソースを同時に変更しないようにするための仕組みです。セマフォーは、それを設定したプロセスしか解除することができません。
  • シグナルとは、1つまたはそれ以上のプロセスが実行を一時停止して、特定のタスクが完了するのを待つようにするための仕組みです。どのプロセスもシグナルで待機したりシグナルをリリースすることができます。

コンピュータープログラムにおけるセマフォーとは、複数のユーザー、またはプロセスによる同時実行が許されない処理を保護するためのツールです。

4D では通常、インタープロセス配列を編集する場合にセマフォーが必要となります。あるプロセスによって配列の値が変更されている間、他のプロセスから同じ処理を同時実行することは、不可能でなくてはなりません。セマフォーを利用することで、ある処理が他のプロセスによって実行中でない場合にのみ、同処理を実行できるよう、特定処理へのアクセスを制御することができます。セマフォーで保護された排他処理にアクセスしようとしたプロセスには、次の可能性があります:

  • プロセスはアクセス権を取得し、処理を実行します。
  • プロセスはアクセス権を得られなかった場合、取得できるまで待機します。
  • プロセスはアクセス権を得られなかった場合、その処理を放棄します。

このようにセマフォーを利用することによって、コードを部分的に保護することができます。処理への同時アクセスをひとつのプロセスに制限し、アクセス権を所持しているプロセスがセマフォーを解放するまで、他のプロセスによる同処理へのアクセスはブロックされます。

4D では、Semaphore 関数をコールすることによってセマフォーを設定します。セマフォーを解放するには、CLEAR SEMAPHORE コマンドをコールします。

Semaphore 関数の動作は特殊で、場合によっては二つのアクションを同時に行うことがあります:

  • セマフォーが他プロセスによって設定済みの場合、TRUE を返します
  • セマフォーが未設定の場合、コール元のプロセスにセマフォーを割り付け、同時に FALSE を返します

必要に応じて、ひとつのコマンドで同時に二つの動作を行うことにより、セマフォーの確認と設定の間に外部処理が割り込むことを防ぎます。

セマフォーの確認だけを行いたい場合には、Test semaphore コマンドを使います。このコマンドは通常、会計の年度締めなどの長い処理の中で使用され、新規データの登録といった特定の操作へアクセスできないよう、インターフェースを制御するのに利用されます。

セマフォーは次のルールに沿って使います:

  • セマフォーの設定と解放は同じメソッドで行います。
  • セマフォーの保護下でのコード実行は可能な限り短くします。
  • セマフォーが解放されるまで待つには、Semaphore 関数の tickCount パラメーターを利用して、待機時間を設定します。

セマフォーを使用するコードの典型例です:

 While(Semaphore("MySemaphore";300))
    IDLE
 End while
  // セマフォーで保護されたコードをここに記載
 CLEAR SEMAPHORE("MySemaphore")

セマフォーが解放されないと、データベースの一部がブロックされたままになります。セマフォーを同一メソッドにて設定・解放することで、このリスクがなくなります。

セマフォーで保護されたコードを最短に抑えることは、セマフォーがボトルネックとなってアプリケーションの性能が低下してしまうのを防ぎます。

また、Semaphore コマンドで任意の tickCount パラメーターを指定することは、セマフォーが解放されるまでの待機を最適化するのに重要です。このパラメーターを使うと、コマンドは次のように動作します:

  • 指定された Tick (1/60秒) 数の時間 (例では 300、つまり 5秒) を限度として、プロセスはコード実行を停止して、セマフォーが解放されるのを待ちます。
  • 指定時間内に解放されたセマフォーはすぐに、待機していたプロセスに割り付けられ (SemaphoreFALSE を返します)、そのプロセスはコード実行を再開します。
  • 指定時間内にセマフォーが解放されなければ、プロセスのコード実行が再開します。

このコマンドはキューを生成し、リクエストの優先順位を管理します。最初にセマフォーを要求したプロセスから順にアクセス権を得る仕組みになっています。

待ち時間は用途に応じて指定するとよいでしょう。

4Dには2種類のセマフォー、ローカルセマフォーとグローバルセマフォーがあります。

  • ローカルセマフォーは、同じワークステーション上のすべてのプロセスからアクセスすることができます (同一ワークステーション上に限られます)。ローカルセマフォーは、セマフォー名の先頭にドル記号 ($) を付けて作成します。ローカルセマフォーは、同一ワークステーション上で実行しているプロセス間で処理を監視するのに使用します。例えば、シングルユーザーデータベースやワークステーション上において、すべてのプロセスに共有されるインタープロセス配列へのアクセスを監視するのにローカルセマフォーを使用します。
  • グローバルセマフォーは、すべてのユーザーおよびプロセスからアクセスすることができます。グローバルセマフォーはマルチユーザデータベースのユーザー間で処理を監視するために用います。

グローバルセマフォーとローカルセマフォーは理論的には同じものです。違いはその有効範囲にあります。

クライアント/サーバーモードでは、グローバルセマフォーはすべてのクライアントおよびサーバーで実行中の全プロセスに共用されます。ローカルセマフォーは、それが作成されたマシン上で実行中のプロセス間でのみ共用されます。

スタンドアロンモードの 4D ではユーザーがひとりしかいないため、グローバルセマフォーもローカルセマフォーもその有効範囲は同じです。ただし、シングルとマルチの両方の形でデータベースを使用する場合は、用途に適したスコープのセマフォーを使い分ける必要があります。

注: インターフェースやインタープロセス変数など、クライアントアプリケーションのローカルな状態を管理するためにセマフォーを使用する場合には、ローカルセマフォーを利用することをお勧めします。このようなケースでグローバルセマフォーを使用すると、不要なネットーワークアクセスが行われるだけでなく、他のクライアントにまで影響を与えかねません。ローカルセマフォーを使用すればこのような望ましくない影響を避けることができます。

シグナルとは、2つのビルトインされたメソッド(signal.wait( ) および signal.trigger( ))を持つ共有オブジェクトで、ワーカーあるいはプロセスを呼び出す/作成するコマンドに対して引数として渡す必要があるものです。

シグナルのsignal.wait( ) メソッドを呼び出すワーカー/プロセスは、どれもsignal.signaled プロパティがtrue になるまでは実行を停止します。シグナルを待っている間、呼び出しているプロセスはCPU を消費しません。これはマルチプロセスアプリケーションでのパフォーマンスとしては珍しい仕組みです。signal.signaled プロパティは、どれかのワーカー/プロセスがシグナルのsignal.trigger( ) メソッドを呼び出した時点でtrue になります。

またブロッキングという状況を避けるため、signal.wait( ) は事前に定義されたtimeout の時間に到達されることでも返されます。

以下の図は、シグナルオブジェクトの使い方を図にまとめたものです:

4D では、New signal ファンクションを呼び出すことで新規シグナルオブジェクトを作成します。作成したあとは、そのシグナルはNew process あるいは CALL WORKER コマンドに引数として渡す必要があります。そうすることでプロセス/ワーカーが、待機しているタスクを完了した際にシグナルを書き換えることができるからです。

シグナルは、signal.wait( ) および signal.trigger( ) の2つのビルトインメソッド、および2つのプロパティ、signal.signaled (読み込みのみ、シグナル作成時はfalse) およびsignal.description (書き込み可能)を持つ共有オブジェクトです。

  • signal.wait( ) は、他のワーカー/プロセスのタスクの完了を待ってから再開するワーカー/プロセスから呼び出す必要があります。
  • signal.trigger( ) は、実行を終えて、他のワーカー/プロセスを待機状態から解放したいワーカー/プロセスから呼び出す必要があります。

signal.trigger( ) の呼び出しを使用して解放された(signal.signaled プロパティがtrue になっている)シグナルは、再度利用することはできません。別のシグナルをまた設定したい場合には、New signal ファンクションをもう一度呼び出す必要があります。

signal オブジェクトは共有オブジェクトであるため(共有オブジェクトと共有コレクション参照)、呼び出されたワーカー/プロセスから結果を返すために使用することもできます。この場合、値を書き込む際にはUse...End use 構造でくくる必要があります(例題参照)。

あるプリエンプティブプロセスで、ユーザーが(例えばダイアログなどから)入力した値が必要な場合を考えます。プリエンプティブプロセスからはダイアログを表示することはできないため、コオペラティブプロセスを呼び出して返される値を待機します:

 C_OBJECT($signal)
 
  // シグナルを作成する
 $signal:=New signal
 
  // メインプロセスを呼び出し、OpenForm メソッドを実行
 CALL WORKER(1;"OpenForm";$signal)
  // 他の計算をする
 ...
  // プロセスの終了を待機
 $signaled:=$signal.wait()
 
  // 結果を処理する
 $calc:=$signal.result+...

OpenForm メソッド:

 C_OBJECT($1;$signal;$form)
 $signal:=$1
 $form:=New object("value";0)
 
  // フォームを開く
 $win:=Open form window("Information";Movable form dialog box)
 DIALOG("Information";$form)
 CLOSE WINDOW($win)
 
  // $signal 共有オブジェクトに新しい属性を追加することで、他のプロセスに返り値を渡す:
 Use($signal)
    $signal.result:=$form.value
 End use
 
  // 待機しているプロセスのシグナルをトリガーする
 $signal.trigger()



参照 

CLEAR SEMAPHORE
Espèce de sémaphore ! (Blog O. Deschanels)
Semaphore
ワーカーについて

 
プロパティ 

プロダクト: 4D
テーマ: プロセス (コミュニケーション)

 
ページの目次 
 
履歴 

変更: 4D v17 R4

 
ARTICLE USAGE

ランゲージリファレンス ( 4D v20)
ランゲージリファレンス ( 4D v20.1)
ランゲージリファレンス ( 4D v20.2)
ランゲージリファレンス ( 4D v20.3)
ランゲージリファレンス ( 4D v20.4)
ランゲージリファレンス ( 4D v20.5)
ランゲージリファレンス ( 4D v20.6)