File tree Expand file tree Collapse file tree 3 files changed +213
-0
lines changed Expand file tree Collapse file tree 3 files changed +213
-0
lines changed Original file line number Diff line number Diff line change 2323require 'concurrent/scheduled_task'
2424require 'concurrent/stoppable'
2525require 'concurrent/supervisor'
26+ require 'concurrent/threadlocalvar'
2627require 'concurrent/timer_task'
2728require 'concurrent/utilities'
2829
Original file line number Diff line number Diff line change 1+ module Concurrent
2+
3+ module ThreadLocalSymbolAllocator
4+
5+ protected
6+
7+ def allocate_symbol
8+ # Warning: this will space leak if you create ThreadLocalVars in a loop - not sure what to do about it
9+ @symbol = "thread_local_symbol_#{ self . object_id } _#{ Time . now . hash } " . to_sym
10+ end
11+
12+ end
13+
14+ module ThreadLocalOldStorage
15+
16+ include ThreadLocalSymbolAllocator
17+
18+ protected
19+
20+ def allocate_storage
21+ allocate_symbol
22+ end
23+
24+ def get
25+ Thread . current [ @symbol ]
26+ end
27+
28+ def set ( value )
29+ Thread . current [ @symbol ] = value
30+ end
31+
32+ end
33+
34+ module ThreadLocalNewStorage
35+
36+ include ThreadLocalSymbolAllocator
37+
38+ protected
39+
40+ def allocate_storage
41+ allocate_symbol
42+ end
43+
44+ def get
45+ Thread . current . thread_variable_get ( @symbol )
46+ end
47+
48+ def set ( value )
49+ Thread . current . thread_variable_set ( @symbol , value )
50+ end
51+
52+ end
53+
54+ module ThreadLocalJavaStorage
55+
56+ protected
57+
58+ def allocate_storage
59+ @var = java . lang . ThreadLocal . new
60+ end
61+
62+ def get
63+ @var . get
64+ end
65+
66+ def set ( value )
67+ @var . set ( value )
68+ end
69+
70+ end
71+
72+ class ThreadLocalVar
73+
74+ NIL_SENTINEL = Object . new
75+
76+ if defined? java . lang . ThreadLocal . new
77+ include ThreadLocalJavaStorage
78+ elsif Thread . current . respond_to? ( :thread_variable_set )
79+ include ThreadLocalNewStorage
80+ else
81+ include ThreadLocalOldStorage
82+ end
83+
84+ def initialize ( default = nil )
85+ @default = default
86+ allocate_storage
87+ end
88+
89+ def value
90+ value = get
91+
92+ if value . nil?
93+ @default
94+ elsif value == NIL_SENTINEL
95+ nil
96+ else
97+ value
98+ end
99+ end
100+
101+ def value = ( value )
102+ if value . nil?
103+ stored_value = NIL_SENTINEL
104+ else
105+ stored_value = value
106+ end
107+
108+ set stored_value
109+
110+ value
111+ end
112+
113+ end
114+
115+ end
Original file line number Diff line number Diff line change 1+ require 'spec_helper'
2+
3+ module Concurrent
4+
5+ describe Future do
6+
7+ context '#initialize' do
8+
9+ it 'can set an initial value' do
10+ v = ThreadLocalVar . new ( 14 )
11+ v . value . should eq 14
12+ end
13+
14+ it 'sets nil as a default initial value' do
15+ v = ThreadLocalVar . new
16+ v . value . should be_nil
17+ end
18+
19+ it 'sets the same initial value for all threads' do
20+ v = ThreadLocalVar . new ( 14 )
21+ t1 = Thread . new { v . value }
22+ t2 = Thread . new { v . value }
23+ t1 . value . should eq 14
24+ t2 . value . should eq 14
25+ end
26+
27+ end
28+
29+ context '#value' do
30+
31+ it 'returns the current value' do
32+ v = ThreadLocalVar . new ( 14 )
33+ v . value . should eq 14
34+ end
35+
36+ it 'returns the value after modification' do
37+ v = ThreadLocalVar . new ( 14 )
38+ v . value = 2
39+ v . value . should eq 2
40+ end
41+
42+ end
43+
44+ context '#value=' do
45+
46+ it 'sets a new value' do
47+ v = ThreadLocalVar . new ( 14 )
48+ v . value = 2
49+ v . value . should eq 2
50+ end
51+
52+ it 'returns the new value' do
53+ v = ThreadLocalVar . new ( 14 )
54+ ( v . value = 2 ) . should eq 2
55+ end
56+
57+ it 'does not modify the initial value for other threads' do
58+ v = ThreadLocalVar . new ( 14 )
59+ v . value = 2
60+ t = Thread . new { v . value }
61+ t . value . should eq 14
62+ end
63+
64+ it 'does not modify the value for other threads' do
65+ v = ThreadLocalVar . new ( 14 )
66+ v . value = 2
67+
68+ b1 = CountDownLatch . new ( 2 )
69+ b2 = CountDownLatch . new ( 2 )
70+
71+ t1 = Thread . new do
72+ b1 . count_down
73+ b1 . wait
74+ v . value = 1
75+ b2 . count_down
76+ b2 . wait
77+ v . value
78+ end
79+
80+ t2 = Thread . new do
81+ b1 . count_down
82+ b1 . wait
83+ v . value = 2
84+ b2 . count_down
85+ b2 . wait
86+ v . value
87+ end
88+
89+ t1 . value . should eq 1
90+ t2 . value . should eq 2
91+ end
92+
93+ end
94+
95+ end
96+
97+ end
You can’t perform that action at this time.
0 commit comments