atomic 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +5 -0
- data/atomic.gemspec +8 -3
- data/examples/bench_atomic.rb +109 -0
- data/lib/atomic.rb +18 -6
- data/lib/atomic_reference.jar +0 -0
- metadata +39 -29
data/Rakefile
CHANGED
data/atomic.gemspec
CHANGED
@@ -2,15 +2,20 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{atomic}
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.6"
|
6
6
|
s.authors = ["Charles Oliver Nutter", "MenTaLguY"]
|
7
7
|
s.date = Time.now.strftime('%Y-%m-%d')
|
8
8
|
s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls"
|
9
9
|
s.email = ["headius@headius.com", "mental@rydia.net"]
|
10
|
-
s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
|
11
10
|
s.homepage = "http://github.com/headius/ruby-atomic"
|
12
11
|
s.require_paths = ["lib"]
|
13
12
|
s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls"
|
14
13
|
s.test_files = Dir["test/test*.rb"]
|
15
|
-
|
14
|
+
if defined?(JRUBY_VERSION)
|
15
|
+
s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
|
16
|
+
s.platform = 'java'
|
17
|
+
else
|
18
|
+
s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
|
19
|
+
s.extensions = 'ext/extconf.rb'
|
20
|
+
end
|
16
21
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'atomic'
|
3
|
+
require 'thread'
|
4
|
+
Thread.abort_on_exception = true
|
5
|
+
|
6
|
+
$go = false # for synchronizing parallel threads
|
7
|
+
|
8
|
+
# number of updates on the value
|
9
|
+
N = ARGV[1] ? ARGV[1].to_i : 100_000
|
10
|
+
|
11
|
+
# number of threads for parallel test
|
12
|
+
M = ARGV[0] ? ARGV[0].to_i : 100
|
13
|
+
|
14
|
+
|
15
|
+
puts "*** Sequential updates ***"
|
16
|
+
Benchmark.bm(10) do |x|
|
17
|
+
value = 0
|
18
|
+
x.report "no lock" do
|
19
|
+
N.times do
|
20
|
+
value += 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@lock = Mutex.new
|
25
|
+
x.report "mutex" do
|
26
|
+
value = 0
|
27
|
+
N.times do
|
28
|
+
@lock.synchronize do
|
29
|
+
value += 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
@atom = Atomic.new(0)
|
35
|
+
x.report "atomic" do
|
36
|
+
N.times do
|
37
|
+
@atom.update{|x| x += 1}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def para_setup(num_threads, count, &block)
|
43
|
+
if num_threads % 2 > 0
|
44
|
+
raise ArgumentError, "num_threads must be a multiple of two"
|
45
|
+
end
|
46
|
+
raise ArgumentError, "need block" unless block_given?
|
47
|
+
|
48
|
+
# Keep those threads together
|
49
|
+
tg = ThreadGroup.new
|
50
|
+
|
51
|
+
num_threads.times do |i|
|
52
|
+
diff = (i % 2 == 0) ? 1 : -1
|
53
|
+
|
54
|
+
t = Thread.new do
|
55
|
+
nil until $go
|
56
|
+
count.times do
|
57
|
+
yield diff
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
tg.add(t)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Make sure all threads are started
|
65
|
+
while tg.list.find{|t| t.status != "run"}
|
66
|
+
Thread.pass
|
67
|
+
end
|
68
|
+
|
69
|
+
# For good measure
|
70
|
+
GC.start
|
71
|
+
|
72
|
+
tg
|
73
|
+
end
|
74
|
+
|
75
|
+
def para_run(tg)
|
76
|
+
$go = true
|
77
|
+
tg.list.each{|t| t.join}
|
78
|
+
$go = false
|
79
|
+
end
|
80
|
+
|
81
|
+
puts "*** Parallel updates ***"
|
82
|
+
Benchmark.bm(10) do |bm|
|
83
|
+
# This is not secure
|
84
|
+
value = 0
|
85
|
+
tg = para_setup(M, N/M) do |diff|
|
86
|
+
value += diff
|
87
|
+
end
|
88
|
+
bm.report("no lock"){ para_run(tg) }
|
89
|
+
|
90
|
+
|
91
|
+
value = 0
|
92
|
+
@lock = Mutex.new
|
93
|
+
tg = para_setup(M, N/M) do |diff|
|
94
|
+
@lock.synchronize do
|
95
|
+
value += diff
|
96
|
+
end
|
97
|
+
end
|
98
|
+
bm.report("mutex"){ para_run(tg) }
|
99
|
+
raise unless value == 0
|
100
|
+
|
101
|
+
|
102
|
+
@atom = Atomic.new(0)
|
103
|
+
tg = para_setup(M, N/M) do |diff|
|
104
|
+
@atom.update{|x| x + diff}
|
105
|
+
end
|
106
|
+
bm.report("atomic"){ para_run(tg) }
|
107
|
+
raise unless @atom.value == 0
|
108
|
+
|
109
|
+
end
|
data/lib/atomic.rb
CHANGED
@@ -11,32 +11,44 @@ class Atomic
|
|
11
11
|
def value
|
12
12
|
@ref.get
|
13
13
|
end
|
14
|
+
alias get value
|
14
15
|
|
15
16
|
def value=(new_value)
|
16
17
|
@ref.set(new_value)
|
17
18
|
new_value
|
18
19
|
end
|
20
|
+
alias set value=
|
19
21
|
|
20
22
|
def swap(new_value)
|
21
23
|
@ref.get_and_set(new_value)
|
22
24
|
end
|
25
|
+
alias get_and_set swap
|
26
|
+
|
27
|
+
def compare_and_swap(old_value, new_value)
|
28
|
+
@ref.compare_and_set(old_value, new_value)
|
29
|
+
end
|
30
|
+
alias compare_and_set compare_and_swap
|
23
31
|
|
24
32
|
# Pass the current value to the given block, replacing it
|
25
33
|
# with the block's result. May retry if the value changes
|
26
34
|
# during the block's execution.
|
27
35
|
def update
|
28
|
-
|
29
|
-
|
30
|
-
rescue ConcurrentUpdateError
|
31
|
-
retry
|
32
|
-
end
|
36
|
+
true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value))
|
37
|
+
new_value
|
33
38
|
end
|
39
|
+
|
40
|
+
# frozen pre-allocated backtrace to speed ConcurrentUpdateError
|
41
|
+
CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
|
34
42
|
|
35
43
|
def try_update
|
36
44
|
old_value = @ref.get
|
37
45
|
new_value = yield old_value
|
38
46
|
unless @ref.compare_and_set(old_value, new_value)
|
39
|
-
|
47
|
+
if $VERBOSE
|
48
|
+
raise ConcurrentUpdateError, "Update failed"
|
49
|
+
else
|
50
|
+
raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE
|
51
|
+
end
|
40
52
|
end
|
41
53
|
new_value
|
42
54
|
end
|
data/lib/atomic_reference.jar
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,43 +1,47 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: atomic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
4
5
|
prerelease:
|
5
|
-
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
6
11
|
platform: ruby
|
7
12
|
authors:
|
8
|
-
|
9
|
-
|
13
|
+
- Charles Oliver Nutter
|
14
|
+
- MenTaLguY
|
10
15
|
autorequire:
|
11
16
|
bindir: bin
|
12
17
|
cert_chain: []
|
13
18
|
|
14
|
-
date: 2011-
|
15
|
-
default_executable:
|
19
|
+
date: 2011-09-06 00:00:00 Z
|
16
20
|
dependencies: []
|
17
21
|
|
18
22
|
description: An atomic reference implementation for JRuby and green or GIL-threaded impls
|
19
23
|
email:
|
20
|
-
|
21
|
-
|
24
|
+
- headius@headius.com
|
25
|
+
- mental@rydia.net
|
22
26
|
executables: []
|
23
27
|
|
24
28
|
extensions:
|
25
|
-
|
29
|
+
- ext/extconf.rb
|
26
30
|
extra_rdoc_files: []
|
27
31
|
|
28
32
|
files:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
- lib/atomic.rb
|
34
|
+
- lib/atomic_reference.jar
|
35
|
+
- examples/atomic_example.rb
|
36
|
+
- examples/bench_atomic.rb
|
37
|
+
- test/test_atomic.rb
|
38
|
+
- ext/atomic_reference.c
|
39
|
+
- ext/AtomicReferenceService.java
|
40
|
+
- ext/extconf.rb
|
41
|
+
- ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java
|
42
|
+
- README.txt
|
43
|
+
- atomic.gemspec
|
44
|
+
- Rakefile
|
41
45
|
homepage: http://github.com/headius/ruby-atomic
|
42
46
|
licenses: []
|
43
47
|
|
@@ -45,25 +49,31 @@ post_install_message:
|
|
45
49
|
rdoc_options: []
|
46
50
|
|
47
51
|
require_paths:
|
48
|
-
|
52
|
+
- lib
|
49
53
|
required_ruby_version: !ruby/object:Gem::Requirement
|
50
54
|
none: false
|
51
55
|
requirements:
|
52
|
-
|
53
|
-
|
54
|
-
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
55
62
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
63
|
none: false
|
57
64
|
requirements:
|
58
|
-
|
59
|
-
|
60
|
-
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
hash: 3
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
61
71
|
requirements: []
|
62
72
|
|
63
73
|
rubyforge_project:
|
64
|
-
rubygems_version: 1.
|
74
|
+
rubygems_version: 1.8.10
|
65
75
|
signing_key:
|
66
76
|
specification_version: 3
|
67
77
|
summary: An atomic reference implementation for JRuby and green or GIL-threaded impls
|
68
78
|
test_files:
|
69
|
-
|
79
|
+
- test/test_atomic.rb
|