use threads; use threads::shared; ... {lock(%h) ... }


ファイルなどの一般的な共有資源に対して排他制御をするときは、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