セマフォとは?共有プロセスのプログラミング方法と例題

問題

(1)以下のような、変数l=1をデクリメントするプロセス1と変数を出力するプロセス2を考える。プロセス1,2が並列で動作した時、プロセス2の表示が必ずl=1,0,1,2と-1刻みで出力されるようにP操作、V操作を空欄1,2に追加せよ。なお、セマフォ変数はs1,s2とし、初期値を示すこと。

(2)次に、変数n=0をインクリメントするプロセス3と変数を出力するプロセス4を考える。本プロセスを並列で実行した結果、printfが2の倍数の出力結果となるようにP操作、V操作を用いて空欄を埋めよ。なお、セマフォ変数はs3,s4とし、初期値を示すこと。

(1)のソースコード

//プロセス1
while (true){
  (空欄1)
  l=l-1;
  (空欄2)
}
//プロセス2
while (true){
  (空欄3)
  print("%d \n",l);
  (空欄4)
}
//出力結果
1
0
-1
-2
-3

(2)のソースコード

//プロセス3
int i;
for(i=0;i<10;i++){
  p(s3);
  n=n+1;
  if((空欄5)){
    (空欄6)
    }else{
    (空欄7);
  }
}
//プロセス4
int i;
for(i=0;i<10;i++){
  (空欄8)
  print("%d \n",n);
  (空欄9)
}
//出力結果
2
4
6
8
10
12
14
16
18
20

セマフォとは

複数のプロセスの間で、リソースへのアクセスを制御するための同期手段を言います。

同期にはP操作V操作を使用します。P操作はプロセスの実行とセットで行います。V操作は、あるプロセスの実行が完了し、待機している別のプロセスを実行したいときに使います。それぞれのプロセスでは、セマフォ変数(ここではsi)をデクリメント(P操作)、インクリメント(V操作)します。siの値が0のときはプロセス実施不可で、1のときは実施可能になります。

本取り決めが無いとあるプロセスが連続で実行されたり、全く実行されないプロセスも出てきます。問で示したような出力結果にはならないことが考えられます。

これをセマフォ変数を適切に設定し、プロセス1を実行すれば次にプロセス2を実行。プロセス2が完了すればプロセス1に戻るを繰り返すことになります。

実際に、問いを解いてみることでP操作とV操作の使い方を見てみましょう。

解答例

(1)セマフォを用いたデクリメントの出力

まず、変数lの初期値が1で、出力結果に1が表示されていることを確認します。これは、変数lを出力するプロセス2が先に実行されていると考えられます。

このため、s1=1,s2=0とし、プロセス2のprintfの前の行(空欄3)にP操作(\P(s_{1})\)を配置することが適切と考えられます。

printfを実行後はプロセス1を実行すればよく、S操作S(s1)を(空欄4)に入れます。その後、プロセス1でP操作P(s1)を実行すれば良いです。(空欄1)

プロセス1側の操作が完了すれば、プロセス2を実行するため、S操作S(s2)を実行すれば良いです。(空欄2)

以上より、下記のコードになります。(s1=0,s2=1)

//プロセス1
while (true){
  P(s2); //空欄1
  l=l-1;
  V(s1); //空欄2
}
//プロセス2
while (true){
  P(s1); //空欄3
  print("%d \n",l);
  V(s2); //空欄4
}
//出力結果
1
0
-1
-2
-3

(2)2の倍数を出力するセマフォ

(1)と同様に考えます。

出力結果に0が無いため、プロセス3を先に実行することが分かります。よって、s3=1,s4=0になります。

インクリメントは1ずつに対し、出力は2の倍数ごとです。1のときは出力しない分岐が必要のため、if文の中の(空欄5)には、i%2==0 が入ります。

if成立時は、printfで出力するためプロセス4を使用する必要があるため、(空欄6)にはV操作V(s4)が入ります。非成立時は、もう一度+1する必要があるためプロセス1を再度動かすためのV操作V(s3)が入ります。(空欄7)

プロセス4では、printfで出力する前にP操作P(s4)をします。(空欄8)出力が完了後は、プロセス3に戻るため、V操作V(s3)が入ります。(空欄9)

以上より、下記のコードになります。

//プロセス3
int i;
for(i=0;i<10;i++){
  p(s3);
  n=n+1;
  if((n%2==0)){
    V(s4)
    }else{
    V(s3);
  }
}
//プロセス4
int i;
for(i=0;i<10;i++){
  P(s4)
  print("%d \n",n);
  V(s3)
}
//出力結果
2
4
6
8
10
12
14
16
18
20

最後に

本問は、応用情報技術者試験でも出題されることがあります。加えて、最近ホットな並列処理を正常に実行するための考え方の一端を勉強することができます。

概念だけでなく、本問を通して実際にプログラミングできるようになれば幸いです。

タイトルとURLをコピーしました