Skip to content

Commit f187c6f

Browse files
committed
Mutex version of atomic reference.
1 parent 82176a7 commit f187c6f

File tree

4 files changed

+186
-1
lines changed

4 files changed

+186
-1
lines changed

lib/concurrent/atomic/atomic.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
module Concurrent
2+
3+
class MutexAtomic
4+
5+
def initialize(init = nil)
6+
@value = init
7+
@mutex = Mutex.new
8+
end
9+
10+
def value
11+
@mutex.lock
12+
result = @value
13+
@mutex.unlock
14+
15+
result
16+
end
17+
18+
def value=(value)
19+
@mutex.lock
20+
result = @value = value
21+
@mutex.unlock
22+
23+
result
24+
end
25+
26+
def modify
27+
@mutex.lock
28+
result = yield @value
29+
@value = result
30+
@mutex.unlock
31+
32+
result
33+
end
34+
35+
def compare_and_set(expect, update)
36+
@mutex.lock
37+
if @value == expect
38+
@value = update
39+
result = true
40+
else
41+
result = false
42+
end
43+
@mutex.unlock
44+
45+
result
46+
end
47+
end
48+
49+
class Atomic < MutexAtomic
50+
end
51+
52+
end

lib/concurrent/atomic/atomic_fixnum.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ def decrement
9595
#
9696
# @return [Boolean] true if the value was updated else false
9797
def compare_and_set(expect, update)
98-
9998
@mutex.lock
10099
if @value == expect
101100
@value = update

lib/concurrent/atomics.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
require 'concurrent/atomic/atomic'
12
require 'concurrent/atomic/atomic_boolean'
23
require 'concurrent/atomic/atomic_fixnum'
34
require 'concurrent/atomic/condition'

spec/concurrent/atomic/atomic_spec.rb

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
require 'spec_helper'
2+
3+
share_examples_for :atomic do
4+
5+
context 'construction' do
6+
7+
it 'sets the initial value' do
8+
described_class.new(:foo).value.should eq :foo
9+
end
10+
11+
it 'defaults the initial value to nil' do
12+
described_class.new.value.should eq nil
13+
end
14+
end
15+
16+
context '#value' do
17+
18+
it 'returns the current value' do
19+
counter = described_class.new(:foo)
20+
counter.value.should eq :foo
21+
end
22+
end
23+
24+
context '#value=' do
25+
26+
it 'sets the #value to the given object' do
27+
atomic = described_class.new(:foo)
28+
atomic.value = :bar
29+
atomic.value.should eq :bar
30+
end
31+
32+
it 'returns the new value' do
33+
atomic = described_class.new(:foo)
34+
(atomic.value = :bar).should eq :bar
35+
end
36+
end
37+
38+
context '#modify' do
39+
40+
it 'yields the current value' do
41+
atomic = described_class.new(:foo)
42+
current = []
43+
atomic.modify { |value| current << value }
44+
current.should eq [:foo]
45+
end
46+
47+
it 'stores the value returned from the yield' do
48+
atomic = described_class.new(:foo)
49+
atomic.modify { |value| :bar }
50+
atomic.value.should eq :bar
51+
end
52+
53+
it 'returns the new value' do
54+
atomic = described_class.new(:foo)
55+
atomic.modify{ |value| :bar }.should eq :bar
56+
end
57+
end
58+
59+
context '#compare_and_set' do
60+
61+
it 'returns false if the value is not found' do
62+
described_class.new(:foo).compare_and_set(:bar, :foo).should eq false
63+
end
64+
65+
it 'returns true if the value is found' do
66+
described_class.new(:foo).compare_and_set(:foo, :bar).should eq true
67+
end
68+
69+
it 'sets if the value is found' do
70+
f = described_class.new(:foo)
71+
f.compare_and_set(:foo, :bar)
72+
f.value.should eq :bar
73+
end
74+
75+
it 'does not set if the value is not found' do
76+
f = described_class.new(:foo)
77+
f.compare_and_set(:bar, :baz)
78+
f.value.should eq :foo
79+
end
80+
end
81+
end
82+
83+
module Concurrent
84+
85+
describe MutexAtomic do
86+
87+
it_should_behave_like :atomic
88+
89+
specify 'construction is synchronized' do
90+
mutex = double('mutex')
91+
Mutex.should_receive(:new).once.with(no_args).and_return(mutex)
92+
described_class.new
93+
end
94+
95+
specify 'value is synchronized' do
96+
mutex = double('mutex')
97+
Mutex.stub(:new).with(no_args).and_return(mutex)
98+
mutex.should_receive(:lock)
99+
mutex.should_receive(:unlock)
100+
described_class.new.value
101+
end
102+
103+
specify 'value= is synchronized' do
104+
mutex = double('mutex')
105+
Mutex.stub(:new).with(no_args).and_return(mutex)
106+
mutex.should_receive(:lock)
107+
mutex.should_receive(:unlock)
108+
described_class.new.value = 10
109+
end
110+
111+
specify 'modify is synchronized' do
112+
mutex = double('mutex')
113+
Mutex.stub(:new).with(no_args).and_return(mutex)
114+
mutex.should_receive(:lock)
115+
mutex.should_receive(:unlock)
116+
described_class.new(:foo).modify { |value| value }
117+
end
118+
119+
specify 'compare_and_set is synchronized' do
120+
mutex = double('mutex')
121+
Mutex.stub(:new).with(no_args).and_return(mutex)
122+
mutex.should_receive(:lock)
123+
mutex.should_receive(:unlock)
124+
described_class.new(14).compare_and_set(14, 2)
125+
end
126+
end
127+
128+
describe Atomic do
129+
it 'inherits from MutexAtomic' do
130+
Atomic.ancestors.should include(MutexAtomic)
131+
end
132+
end
133+
end

0 commit comments

Comments
 (0)