必要性をあまり感じたことがないし、なんだかややこしい。
うかつに使うとこういうことになる。という図を書いて置いとく。
なにが怖いんだっけ?とか考えなくてすむように
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Foo
@@foo = 999
def self.xxx(num)
@@foo = num
puts "#{num}:#{@@foo}"
puts "#{num}:#{@@foo}"
end
end
threads = []
10.times do |i|
threads << Thread.new do
Foo.xxx(i)
end
end
threads.each(&:join)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1:1
2:2
3:3
1:3
5:5
4:4
6:6
6:6
7:7
8:8
9:9
9:9
0:9
3:9
2:9
5:9
4:9
7:9
8:9
ステップに割り込まれて他のスレッドに書き換えられちゃってますね。
こわ。注意しましょう。
こんなクソ例だとシングルトンでも一緒ですね。
適切な例が思いつかない。定数とインスタンス変数で十分な人生だったということか。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Bar
include Singleton
def set_bar(num)
@bar = num
end
def bar
@bar
end
end
class Baz
def self.xxx(num)
Bar.instance.set_bar(num)
puts "#{num}:#{Bar.instance.bar}"
puts "#{num}:#{Bar.instance.bar}"
end
end
threads = []
10.times do |i|
threads << Thread.new do
Baz.xxx(i)
end
end
threads.each(&:join)
0:0
3:3
3:3
0:3
2:2
4:4
4:4
5:5
7:7
6:6
8:8
9:9
1:8
2:8
5:8
6:8
7:8
9:8
8:8
ちなみに排他制御したいときは Thread::Mutex
を使うと良いようだ
このバカ例ならループで十分だけど。。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Foo
@@foo = 999
def self.xxx(num)
@@foo = num
puts "#{num}:#{@@foo}"
puts "#{num}:#{@@foo}"
end
end
threads = []
100.times do |i|
threads << Thread::Mutex.new.synchronize do
Foo.xxx(i)
end
end
0:0
0:0
1:1
1:1
2:2
2:2
3:3
3:3
4:4
4:4
5:5
5:5
6:6
6:6
7:7
7:7
8:8
8:8
9:9
9:9
コメント