tsafe 0.0.6 → 0.0.9
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/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"
|