承前; threads::shared で変数を共有してみる

とりあえず mod_perl を離れて threads::shared でスレッド間変数共有をやってみましょう。

package Counter;

use strict;
use threads;
use threads::shared;

my $counter :shared = 0;

sub counter {
  return ++ $counter;
}

1;

昨日と同じようなカウンタをインプリメントしてみました(ほんとはカウントアップ部分がアトミックな保証がないのでロックするなりセマフォ使うなりするべきですが)。これを外部スクリプトから使います。

#!/usr/bin/perl

use strict;
use threads;
use Time::HiRes qw( usleep );
use Counter;

sub thread_main {
  for (1 .. 5) {
    usleep int(rand(10) + 1) * 100_000;
    print STDERR sprintf("%d: %d\n", threads->tid(), Counter::counter());
  }
}

my $th1 = threads->create(\&thread_main);
my $th2 = threads->create(\&thread_main);
$th1->join();
$th2->join();

時間がかかるのが嫌なんで Time::HiRes::usleep を使っていますが,気長な方は普通に sleep を使ってもいいです。スレッドを2個作ってから両者を join してます。順番間違えるとマルチスレッドの意味が無くなってしまいます。

で,実行結果は,

2: 1
1: 2
1: 3
2: 4
1: 5
2: 6
1: 7
2: 8
2: 9
1: 10

2つのスレッドで変数が共有されていることがわかります。

あら,うまくいってるじゃん。

ということで昨日のクイズのヒントです。外部スクリプトを下記のように書き換えます。

#!/usr/bin/perl

use strict;
use threads;
use Time::HiRes qw( usleep );
#use Counter;

sub thread_main {
  require Counter;

  for (1 .. 5) {
    usleep int(rand(10) + 1) * 100_000;
    print STDERR sprintf("%d: %d\n", threads->tid(), Counter::counter());
  }
}

my $th1 = threads->create(\&thread_main);
my $th2 = threads->create(\&thread_main);
$th1->join();
$th2->join();

この実行結果は,

1: 1
2: 1
1: 2
1: 3
1: 4
2: 2
2: 3
1: 5
2: 4
2: 5

2つのスレッドでカウンタ値が別々に保持されていることがわかります。

以下明日以降に続きます。