Threads[ConditionVariable] パッケージの概要
使い方
Threads[ConditionVariable][command](arguments)
command(arguments)
|
説明
|
|
•
|
Threads[ConditionVariable] パッケージは状態変数をユーザレベルで使うコマンドを提供します。状態変数は複数のスレッドの仕事を同期されるために使い増す。状態変数は反復のよりよい実装をすることが可能です。これらは特定の仕事が実行されるまでスレッドは待機し、それから再び実行します。
|
•
|
状態変数を使うと、スレッドは命令を待ち待機している他のスレッドを停止させることができます。停止しているスレッドに信号を送っているスレッドは 1 つのスレッドをスタートさせるか、ある状態変数を持つすべてのスレッドを待機させるかのいずれかのオプションを持ちます。
|
•
|
複数のスレッドが状態変数で待機中で 1 つだけ動いているとき、スレッドが動いているかは保障できません。
|
•
|
状態変数を使うときミューテックスも必要です。状態変数を使う前にミューテックスの使い方と知っておく必要があります。
|
•
|
状態変数を使う基本的な状況として、複数のスレッドが動いていていくつかの点でデータの変更が必要となるときがあります。あるスレッドがその点に到達するため、データを共有の場所におき、ある状態変数で待機します。最後のスレッドが同時に到達するとき、起動するためその他のスレッドに命令することができ、すべてのスレッドが共有データとしてアクセスすることができます。
|
•
|
他の例として生産者 - 消費者 (Producer/Consume) パターンがあります。このパターンの中では、ものを生産する生産者のスレッドが 1 つあります。もう一つ、ものを消費する消費者のスレッドがあります。
もし消費者スレッドが物を処理するものがないとき、ある状態変数で待機することによって停止をします。生産者スレッドが物を生産できるとき、ある状態変数で待機しているスレッドに仕事をさせることを命令することができます。
|
|
|
例
|
|
これは生産者 - 消費者 (Producer/Consume) パターンの例です。
生産者は物を生産します (ここでは大域テーブルのタブ内の整数で表します) 。消費者は物があればを消費し、結果をテーブルの最後に挿入します。
2 つの状態変数と 1 つのミューテックスを持ちます。1 つ目の状態変数 (cp) は生産者のスレッドとして使います。生産者スレッドは、仕事がいっぱいであれば生産者の状態変数は待機します。もう一つの状態変数 (cc) は消費者が使います。物がない場合、消費者スレッドは生産者が物を作るまで待機します。
ミューテックスは大域変数タブへのアクセスを制御するために使います。
>
|
Producer := proc( m, cp, cc, max, mindiff )
global tab, e;
local i,j,n;
Threads:-Mutex:-Lock( m );
j := 0;
tab[ "maxjob" ] := mindiff;
tab[ "curjob" ] := 1;
for j from 1 to mindiff
do
tab[ j ] := 2*j;
end do;
Threads:-ConditionVariable:-Signal( cp );
Threads:-Mutex:-Unlock( m );
n := false;
while ( e )
do
Threads:-Mutex:-Lock( m );
j := tab[ "maxjob" ];
if ( j - tab[ "curjob" ] > mindiff/2 ) then
n := true;
Threads:-ConditionVariable:-Wait( cp, m );
end if;
for i from j to tab[ "curjob" ] + mindiff
do
tab[ i ] := 2*i;
end do;
tab[ "maxjob" ] := tab[ "curjob" ] + mindiff;
if ( n ) then
Threads:-ConditionVariable:-Broadcast( cc );
n := false;
end if;
Threads:-Mutex:-Unlock( m );
end do;
end proc:
|
>
|
Consumer := proc( m, cp, cc, max )
global tab, e;
local n, i, j, num;
num := 0;
while ( num < max )
do
Threads:-Mutex:-Lock( m );
while ( tab[ "curjob" ] = tab[ "maxjob" ] )
do
Threads:-ConditionVariable:-Signal( cp );
Threads:-ConditionVariable:-Wait( cc, m );
end do;
n := tab[ "curjob" ];
j := tab[ n ];
tab[ "curjob" ] := n + 1;
Threads:-Mutex:-Unlock( m );
j := add( i, i=1..j );
num := num+1;
Threads:-Mutex:-Lock( m );
tab[ n ] := j;
Threads:-Mutex:-Unlock( m );
end do;
end proc:
|
>
|
tab := table( ):
m := Threads:-Mutex:-Create();
|
>
|
cc := Threads:-ConditionVariable:-Create();
|
>
|
cp := Threads:-ConditionVariable:-Create();
|
生産者スレッドをスタートします。生産者スレッドがスタートするまで cp は待機しています。
>
|
Threads:-Mutex:-Lock( m );
id1 := Threads:-Create( Producer( m, cp, cc, 31, 10 ) );
|
>
|
Threads:-ConditionVariable:-Wait( cp, m );
Threads:-Mutex:-Unlock( m );
|
消費者スレッドをスタートします。毎回 100 個の物を消費し、5 つのスレッドで行うので 500 個の物を消費します。
>
|
id2 := [ seq( Threads:-Create( Consumer( m, cp, cc, 100 ) ), i=1..5 ) ];
|
終わるまで消費者スレッドを待機します。
>
|
Threads:-Wait( op( id2 ) );
Threads:-Mutex:-Lock( m );
|
生産者スレッドを終了します。
>
|
e := false:
Threads:-ConditionVariable:-Signal( cp );
Threads:-Mutex:-Unlock( m );
Threads:-Wait( id1 );
|
仕事の数を調べます。
>
|
print( tab[ "curjob" ] );
|
仕事の結果を調べます。
>
|
print( add( i, i=1..2*233 ) );
|
|
|