File tree Expand file tree Collapse file tree 3 files changed +174
-0
lines changed Expand file tree Collapse file tree 3 files changed +174
-0
lines changed Original file line number Diff line number Diff line change 13
13
require 'concurrent/dereferenceable'
14
14
require 'concurrent/event'
15
15
require 'concurrent/future'
16
+ require 'concurrent/mvar'
16
17
require 'concurrent/obligation'
17
18
require 'concurrent/postable'
18
19
require 'concurrent/promise'
Original file line number Diff line number Diff line change
1
+ require 'concurrent/event'
2
+
3
+ module Concurrent
4
+
5
+ class MVar
6
+
7
+ EMPTY = Object . new
8
+ TIMEOUT = Object . new
9
+
10
+ def initialize ( value = EMPTY )
11
+ @value = value
12
+ @mutex = Mutex . new
13
+ @empty_condition = ConditionVariable . new
14
+ @full_condition = ConditionVariable . new
15
+ end
16
+
17
+ def take ( timeout = nil )
18
+ @mutex . synchronize do
19
+ # If the value isn't empty, wait for full to be signalled
20
+ @full_condition . wait ( @mutex , timeout ) if empty?
21
+
22
+ # If we timed out we'll still be empty
23
+ if not empty?
24
+ value = @value
25
+ @value = EMPTY
26
+ @empty_condition . signal
27
+ value
28
+ else
29
+ TIMEOUT
30
+ end
31
+ end
32
+
33
+
34
+ end
35
+
36
+ def put ( value , timeout = nil )
37
+ @mutex . synchronize do
38
+ # Unless the value is empty, wait for empty to be signalled
39
+ @empty_condition . wait ( @mutex , timeout ) unless empty?
40
+
41
+ # If we timed out we won't be empty
42
+ if empty?
43
+ @value = value
44
+ @full_condition . signal
45
+ value
46
+ else
47
+ TIMEOUT
48
+ end
49
+ end
50
+ end
51
+
52
+ def empty?
53
+ @value == EMPTY
54
+ end
55
+
56
+ end
57
+
58
+ end
Original file line number Diff line number Diff line change
1
+ require 'spec_helper'
2
+
3
+ module Concurrent
4
+
5
+ describe MVar do
6
+
7
+ context '#initialize' do
8
+
9
+ it 'accepts no initial value' do
10
+ m = MVar . new
11
+ m . should be_empty
12
+ end
13
+
14
+ it 'accepts an empty initial value' do
15
+ m = MVar . new ( MVar ::EMPTY )
16
+ m . should be_empty
17
+ end
18
+
19
+ it 'accepts an initial value' do
20
+ m = MVar . new ( 14 )
21
+ m . should_not be_empty
22
+ end
23
+
24
+ it 'accepts a nil initial value' do
25
+ m = MVar . new ( nil )
26
+ m . should_not be_empty
27
+ end
28
+
29
+ end
30
+
31
+ context '#take' do
32
+
33
+ it 'sets the MVar to empty' do
34
+ m = MVar . new ( 14 )
35
+ m . take
36
+ m . should be_empty
37
+ end
38
+
39
+ it 'returns the value on a full MVar' do
40
+ m = MVar . new ( 14 )
41
+ m . take . should eq 14
42
+ end
43
+
44
+ it 'waits for another thread to #put' do
45
+ m = MVar . new
46
+
47
+ putter = Thread . new {
48
+ sleep ( 0.5 )
49
+ m . put 14
50
+ }
51
+
52
+ m . take . should eq 14
53
+ end
54
+
55
+ it 'returns TIMEOUT on timeout on an empty MVar' do
56
+ m = MVar . new
57
+ m . take ( 0.5 ) . should eq MVar ::TIMEOUT
58
+ end
59
+
60
+ end
61
+
62
+ context '#put' do
63
+
64
+ it 'sets the MVar to be empty' do
65
+ m = MVar . new ( 14 )
66
+ m . take
67
+ m . should be_empty
68
+ end
69
+
70
+ it 'sets a new value on an empty MVar' do
71
+ m = MVar . new
72
+ m . put 14
73
+ m . take . should eq 14
74
+ end
75
+
76
+ it 'waits for another thread to #take' do
77
+ m = MVar . new ( 14 )
78
+
79
+ putter = Thread . new {
80
+ sleep ( 0.5 )
81
+ m . take
82
+ }
83
+
84
+ m . put ( 14 ) . should eq 14
85
+ end
86
+
87
+ it 'returns TIMEOUT on timeout on a full MVar' do
88
+ m = MVar . new ( 14 )
89
+ m . put ( 14 , 0.5 ) . should eq MVar ::TIMEOUT
90
+ end
91
+
92
+ it 'returns the value' do
93
+ m = MVar . new
94
+ m . put ( 14 ) . should eq 14
95
+ end
96
+
97
+ end
98
+
99
+ context '#empty' do
100
+
101
+ it 'returns true on an empty MVar' do
102
+ m = MVar . new
103
+ m . should be_empty
104
+ end
105
+
106
+ it 'returns false on a full MVar' do
107
+ m = MVar . new ( 14 )
108
+ m . should_not be_empty
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+
115
+ end
You can’t perform that action at this time.
0 commit comments