tsafe 0.0.6 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/lib/tsafe.rb +10 -3
- data/lib/tsafe_monarray.rb +1 -1
- data/lib/tsafe_monhash.rb +1 -1
- data/lib/tsafe_mrswlock.rb +5 -79
- data/lib/tsafe_mrswlock_jruby.rb +45 -0
- data/lib/tsafe_mrswlock_synmodule.rb +63 -0
- data/tsafe.gemspec +4 -2
- metadata +5 -3
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.9
|
data/lib/tsafe.rb
CHANGED
@@ -4,14 +4,21 @@ require "monitor"
|
|
4
4
|
module Tsafe
|
5
5
|
#Autoloader for subclasses.
|
6
6
|
def self.const_missing(name)
|
7
|
-
|
7
|
+
filep = "#{File.dirname(__FILE__)}/tsafe_#{name.to_s.downcase}"
|
8
|
+
|
9
|
+
if RUBY_ENGINE == "jruby" and File.exists?("#{filep}_jruby.rb")
|
10
|
+
require "#{filep}_jruby.rb"
|
11
|
+
else
|
12
|
+
require filep
|
13
|
+
end
|
14
|
+
|
8
15
|
raise "Still not loaded: '#{name}'." if !Tsafe.const_defined?(name)
|
9
16
|
return Tsafe.const_get(name)
|
10
17
|
end
|
11
18
|
|
12
|
-
#JRuby can corrupt an array in a threadded env. Use this method to only get a synchronized array when running JRuby
|
19
|
+
#JRuby can corrupt an array in a threadded env. Use this method to only get a synchronized array when running JRuby in order to not having to write "if RUBY_ENGINE"-stuff.
|
13
20
|
def self.std_array
|
14
|
-
return MonArray.new if RUBY_ENGINE == "jruby"
|
21
|
+
return Tsafe::MonArray.new if RUBY_ENGINE == "jruby"
|
15
22
|
return []
|
16
23
|
end
|
17
24
|
end
|
data/lib/tsafe_monarray.rb
CHANGED
@@ -8,5 +8,5 @@ class Tsafe::MonArray < ::Array
|
|
8
8
|
@@tsafe_rwmutex_w_methods = [:<<, :collect, :collect!, :compact!, :delete, :delete_at, :delete_if, :drop, :drop_while, :fill, :flatten!, :insert, :keep_if, :map, :map!, :replace, :shuffle!, :slice!, :shift, :sort!, :sort_by!, :unshift]
|
9
9
|
@@tsafe_rwmutex_r_methods = [:each, :each_index, :take_while]
|
10
10
|
|
11
|
-
include Tsafe::
|
11
|
+
include Tsafe::Mrswlock_synmodule
|
12
12
|
end
|
data/lib/tsafe_monhash.rb
CHANGED
@@ -8,5 +8,5 @@ class Tsafe::MonHash < ::Hash
|
|
8
8
|
@@tsafe_mrswlock_w_methods = [:[]=, :clear, :delete, :delete_if, :keep_if, :merge!, :rehash, :reject!, :replace, :select!, :shift, :store, :update, :values_at]
|
9
9
|
@@tsafe_mrswlock_r_methods = [:each, :each_key, :each_pair, :each_value]
|
10
10
|
|
11
|
-
include Tsafe::
|
11
|
+
include Tsafe::Mrswlock_synmodule
|
12
12
|
end
|
data/lib/tsafe_mrswlock.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
#A class that allows many simultanious read-synchronizations but locks both reading and writing while calling the write-synchronzie-method.
|
1
|
+
# A class that allows many simultanious read-synchronizations but locks both reading and writing while calling the write-synchronzie-method.
|
2
|
+
# This version does not work in JRuby! 'const_missing'-autoloader should automatically load the JRuby-version.
|
3
|
+
# It is not 'actually' thread-safe, but because of GIL, it wont bug up. If it was actually thread-safe, the performance would go down. So it only works with GIL.
|
2
4
|
class Tsafe::Mrswlock
|
3
|
-
@@debug = false
|
4
|
-
|
5
5
|
# Sets various variables.
|
6
6
|
def initialize
|
7
7
|
@reads = 0
|
@@ -18,15 +18,9 @@ class Tsafe::Mrswlock
|
|
18
18
|
def rsync
|
19
19
|
begin
|
20
20
|
tid = Thread.current.__id__
|
21
|
-
|
22
|
-
while @w_mutex.locked? and @locked_by != tid
|
23
|
-
Thread.pass
|
24
|
-
print "Passed because lock.\n" if @@debug
|
25
|
-
end
|
26
|
-
|
21
|
+
Thread.pass while @w_mutex.locked? and @locked_by != tid
|
27
22
|
@reading_threads[tid] = true
|
28
23
|
@reads += 1
|
29
|
-
print "Reading more than one at a time! (#{@reads})\n" if @@debug and @reads >= 2
|
30
24
|
yield
|
31
25
|
ensure
|
32
26
|
@reading_threads.delete(tid)
|
@@ -48,12 +42,8 @@ class Tsafe::Mrswlock
|
|
48
42
|
#Wait for any reads to finish that might have started while we were getting the lock.
|
49
43
|
#Also allow write if there is only one reading thread and that reading thread is the current thread.
|
50
44
|
while @reads > 0
|
51
|
-
if @reading_threads.key?(tid)
|
52
|
-
raise ThreadError, "Deadlock: Writing is not allowed while reading."
|
53
|
-
end
|
54
|
-
|
45
|
+
raise ThreadError, "Deadlock: Writing is not allowed while reading." if @reading_threads.key?(tid)
|
55
46
|
Thread.pass
|
56
|
-
print "Passed because reading.\n" if @@debug
|
57
47
|
end
|
58
48
|
|
59
49
|
yield
|
@@ -62,68 +52,4 @@ class Tsafe::Mrswlock
|
|
62
52
|
end
|
63
53
|
end
|
64
54
|
end
|
65
|
-
|
66
|
-
#This module can be included in order to painlessly make a thread-safe multi-reader-single-writer thread-safe copy of a class.
|
67
|
-
#===Examples
|
68
|
-
# class Tsafe::MonHash < ::Hash
|
69
|
-
# @@tsafe_mrswlock_w_methods = [:[]=, :clear, :delete, :delete_if, :keep_if, :merge!, :rehash, :reject!, :replace, :select!, :shift, :store, :update, :values_at]
|
70
|
-
# @@tsafe_mrswlock_r_methods = [:each, :each_key, :each_pair, :each_value]
|
71
|
-
# include Tsafe::Mrswlock::SynModule
|
72
|
-
# end
|
73
|
-
module SynModule
|
74
|
-
def self.included(base)
|
75
|
-
base.to_s.split("::").inject(Object, :const_get).class_eval do
|
76
|
-
#Yields the given block within the read-lock.
|
77
|
-
#===Examples
|
78
|
-
# obj._tsafe_rsync do
|
79
|
-
# #do something within read-lock.
|
80
|
-
# end
|
81
|
-
def _tsafe_rsync(&block)
|
82
|
-
@tsafe_mrswlock.rsync(&block)
|
83
|
-
end
|
84
|
-
|
85
|
-
#Yields the given block within the write-lock (and read-lock).
|
86
|
-
#===Examples
|
87
|
-
# obj._tsafe_wsync do
|
88
|
-
# #do something within write-lock.
|
89
|
-
# end
|
90
|
-
def _tsafe_wsync(&block)
|
91
|
-
@tsafe_mrswlock.rsync(&block)
|
92
|
-
end
|
93
|
-
|
94
|
-
#Rename initialize.
|
95
|
-
alias_method(:initialize_mrswlock, :initialize)
|
96
|
-
|
97
|
-
#Make another initialize-method that spawns the lock and then calls the original initialize.
|
98
|
-
define_method(:initialize) do |*args, &block|
|
99
|
-
@tsafe_mrswlock = Tsafe::Mrswlock.new
|
100
|
-
return initialize_mrswlock(*args, &block)
|
101
|
-
end
|
102
|
-
|
103
|
-
#Makes reader methods go through reader-lock.
|
104
|
-
base.class_variable_get(:@@tsafe_mrswlock_r_methods).each do |mname|
|
105
|
-
newmname = "tsafe_mrswlock_#{mname}".to_sym
|
106
|
-
alias_method(newmname, mname)
|
107
|
-
|
108
|
-
define_method(mname) do |*args, &block|
|
109
|
-
@tsafe_mrswlock.rsync do
|
110
|
-
return self.__send__(newmname, *args, &block)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
#Makes writer methods go through writer-lock.
|
116
|
-
base.class_variable_get(:@@tsafe_mrswlock_w_methods).each do |mname|
|
117
|
-
newmname = "tsafe_mrswlock_#{mname}".to_sym
|
118
|
-
alias_method(newmname, mname)
|
119
|
-
|
120
|
-
define_method(mname) do |*args, &block|
|
121
|
-
@tsafe_mrswlock.wsync do
|
122
|
-
return self.__send__(newmname, *args, &block)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
55
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "java"
|
2
|
+
|
3
|
+
# A class that allows many simultanious read-synchronizations but locks both reading and writing while calling the write-synchronzie-method.
|
4
|
+
# This is the JRuby-version and will not work under anything else. It uses 'java.util.concurrent.locks.ReentrantReadWriteLock' instead of doing the locking in Ruby.
|
5
|
+
class Tsafe::Mrswlock
|
6
|
+
# Sets various variables.
|
7
|
+
def initialize
|
8
|
+
@lock = java.util.concurrent.locks.ReentrantReadWriteLock.new
|
9
|
+
|
10
|
+
#This hash holds thread-IDs for threads that are reading.
|
11
|
+
@reading_threads = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Runs the given block through the read-synchronization.
|
15
|
+
def rsync
|
16
|
+
@lock.read_lock.lock
|
17
|
+
tid = Thread.current.__id__
|
18
|
+
@reading_threads[tid] = true
|
19
|
+
|
20
|
+
begin
|
21
|
+
yield
|
22
|
+
ensure
|
23
|
+
@reading_threads.delete(tid)
|
24
|
+
@lock.read_lock.unlock
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#Runs the given block through the write-synchronization (locks both reading and writing).
|
29
|
+
#===Examples
|
30
|
+
# lock.wsync do
|
31
|
+
# #do something within lock.
|
32
|
+
# end
|
33
|
+
def wsync
|
34
|
+
tid = Thread.current.__id__
|
35
|
+
raise ThreadError, "Deadlock: Writing is not allowed while reading." if @reading_threads.key?(tid)
|
36
|
+
|
37
|
+
begin
|
38
|
+
@wlock_by = tid
|
39
|
+
@lock.write_lock.lock
|
40
|
+
yield
|
41
|
+
ensure
|
42
|
+
@lock.write_lock.unlock
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# This module can be included in order to painlessly make a thread-safe multi-reader-single-writer thread-safe copy of a class.
|
2
|
+
#===Examples
|
3
|
+
# class Tsafe::MonHash < ::Hash
|
4
|
+
# @@tsafe_mrswlock_w_methods = [:[]=, :clear, :delete, :delete_if, :keep_if, :merge!, :rehash, :reject!, :replace, :select!, :shift, :store, :update, :values_at]
|
5
|
+
# @@tsafe_mrswlock_r_methods = [:each, :each_key, :each_pair, :each_value]
|
6
|
+
# include Tsafe::Mrswlock::SynModule
|
7
|
+
# end
|
8
|
+
module Tsafe::Mrswlock_synmodule
|
9
|
+
def self.included(base)
|
10
|
+
base.to_s.split("::").inject(Object, :const_get).class_eval do
|
11
|
+
#Yields the given block within the read-lock.
|
12
|
+
#===Examples
|
13
|
+
# obj._tsafe_rsync do
|
14
|
+
# #do something within read-lock.
|
15
|
+
# end
|
16
|
+
def _tsafe_rsync(&block)
|
17
|
+
@tsafe_mrswlock.rsync(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
#Yields the given block within the write-lock (and read-lock).
|
21
|
+
#===Examples
|
22
|
+
# obj._tsafe_wsync do
|
23
|
+
# #do something within write-lock.
|
24
|
+
# end
|
25
|
+
def _tsafe_wsync(&block)
|
26
|
+
@tsafe_mrswlock.rsync(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
#Rename initialize.
|
30
|
+
alias_method(:initialize_mrswlock, :initialize)
|
31
|
+
|
32
|
+
#Make another initialize-method that spawns the lock and then calls the original initialize.
|
33
|
+
define_method(:initialize) do |*args, &block|
|
34
|
+
@tsafe_mrswlock = Tsafe::Mrswlock.new
|
35
|
+
return initialize_mrswlock(*args, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
#Makes reader methods go through reader-lock.
|
39
|
+
base.class_variable_get(:@@tsafe_mrswlock_r_methods).each do |mname|
|
40
|
+
newmname = "tsafe_mrswlock_#{mname}".to_sym
|
41
|
+
alias_method(newmname, mname)
|
42
|
+
|
43
|
+
define_method(mname) do |*args, &block|
|
44
|
+
@tsafe_mrswlock.rsync do
|
45
|
+
return self.__send__(newmname, *args, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#Makes writer methods go through writer-lock.
|
51
|
+
base.class_variable_get(:@@tsafe_mrswlock_w_methods).each do |mname|
|
52
|
+
newmname = "tsafe_mrswlock_#{mname}".to_sym
|
53
|
+
alias_method(newmname, mname)
|
54
|
+
|
55
|
+
define_method(mname) do |*args, &block|
|
56
|
+
@tsafe_mrswlock.wsync do
|
57
|
+
return self.__send__(newmname, *args, &block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/tsafe.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tsafe}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kasper Johansen"]
|
12
|
-
s.date = %q{2012-07-
|
12
|
+
s.date = %q{2012-07-27}
|
13
13
|
s.description = %q{Proxy-objects for making another object threadsafe by proxying calls through mutex and method_missing. Monitored array and hash where all methods are going through monitor. Threadsafe class for including into a class that extends another class in order to make it threadsafe.}
|
14
14
|
s.email = %q{k@spernj.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -30,6 +30,8 @@ Gem::Specification.new do |s|
|
|
30
30
|
"lib/tsafe_monhash.rb",
|
31
31
|
"lib/tsafe_monitored.rb",
|
32
32
|
"lib/tsafe_mrswlock.rb",
|
33
|
+
"lib/tsafe_mrswlock_jruby.rb",
|
34
|
+
"lib/tsafe_mrswlock_synmodule.rb",
|
33
35
|
"lib/tsafe_mutexed.rb",
|
34
36
|
"lib/tsafe_proxy.rb",
|
35
37
|
"spec/mrswlock_spec.rb",
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: tsafe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.9
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Kasper Johansen
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-07-
|
13
|
+
date: 2012-07-27 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -80,6 +80,8 @@ files:
|
|
80
80
|
- lib/tsafe_monhash.rb
|
81
81
|
- lib/tsafe_monitored.rb
|
82
82
|
- lib/tsafe_mrswlock.rb
|
83
|
+
- lib/tsafe_mrswlock_jruby.rb
|
84
|
+
- lib/tsafe_mrswlock_synmodule.rb
|
83
85
|
- lib/tsafe_mutexed.rb
|
84
86
|
- lib/tsafe_proxy.rb
|
85
87
|
- spec/mrswlock_spec.rb
|
@@ -100,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
102
|
requirements:
|
101
103
|
- - ">="
|
102
104
|
- !ruby/object:Gem::Version
|
103
|
-
hash:
|
105
|
+
hash: 3863386299653534485
|
104
106
|
segments:
|
105
107
|
- 0
|
106
108
|
version: "0"
|