ファイルなどの一般的な共有資源に対して排他制御をするときは、flock()もしくは、
use Thread::Semaphore;をしてセマフォを生成する。
スレッド間の共有変数に対して排他制御を掛ける時はlock()。
簡単なlockを使った排他制御を試してみた。
lock関数は引数にしている変数の排他制御を行い、スコープから外れると自動的に開放してくれる。
my ($sec, $microsec); use Time::HiRes qw(gettimeofday); BEGIN{ ($sec, $microsec) = gettimeofday;}# 処理実行前の時間を取得 use threads; use threads::shared; my %h :shared = (); # スレッド間の共有変数%h my @thr =(); # スレッドの配列 foreach(1..100){ push(@thr, new threads(\&test_thread));} foreach(@thr){ $_->join(); } foreach(sort {$a <=> $b} keys %h){ printf ("key-%d : %d (%s)\n", $_, $h{$_}, ($h{$_} == @thr ? "true" : "false")); } printf("user: %s\nsystem: %s\nc_user: %s\nc_system: %s\n", times); my ($sec2, $microsec2) = gettimeofday; printf("time:%f\n", ($sec2+$microsec2/1000000)-($sec+$microsec/1000000)); # スレッド用の関数 sub test_thread(){ foreach(1..100){ # lock(%h); # コメントアウトしたりしなかったりしてみる for(1..10000){1;} $h{$_}++; } }
lock()無し
...
key-96 : 100 (true)
key-97 : 99 (false)
key-98 : 100 (true)
key-99 : 100 (true)
key-100 : 100 (true)
user: 6.593
system: 0.234
c_user: 0
c_system: 0
time:2.031250
lock()有り
...
key-96 : 100 (true)
key-97 : 100 (true)
key-98 : 100 (true)
key-99 : 100 (true)
key-100 : 100 (true)
user: 6.312
system: 0.171
c_user: 0
c_system: 0
time:5.718750
4コア環境なので、スレッド処理がフルに生きているlock無しなら中々早く終わるが、
排他制御を行っていないため、いくつか整合性を保てなかった。
一方、lock有りは整合性を保てていたが、一番処理時間がかかる部分も含めて排他制御をしているため、実行時間がほとんどシングルスレッドと変わらない。
ただこの場合は、ループ内で共有変数を使っていないので、lockはそれを終えてからやっても遅くないわけで。
for(1..10000){1;} lock(%h); $h{$_}++;
...
key-95 : 100 (true)
key-96 : 100 (true)
key-97 : 100 (true)
key-98 : 100 (true)
key-99 : 100 (true)
key-100 : 100 (true)
user: 6.593
system: 0.187
c_user: 0
c_system: 0
time:2.031250