tsafe 0.0.1 → 0.0.2

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 CHANGED
@@ -3,12 +3,12 @@ GEM
3
3
  specs:
4
4
  diff-lcs (1.1.3)
5
5
  git (1.2.5)
6
- jeweler (1.8.3)
6
+ jeweler (1.8.4)
7
7
  bundler (~> 1.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
10
  rdoc
11
- json (1.7.1)
11
+ json (1.7.3)
12
12
  rake (0.9.2.2)
13
13
  rdoc (3.12)
14
14
  json (~> 1.4)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -0,0 +1,12 @@
1
+ #Predefined synchronized array.
2
+ #
3
+ #===Examples
4
+ # arr = Tsafe::MonArray.new
5
+ # arr << 5
6
+ # ret = arr[0]
7
+ class Tsafe::MonArray < ::Array
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
+ @@tsafe_rwmutex_r_methods = [:each, :each_index, :take_while]
10
+
11
+ include Tsafe::SynModule
12
+ end
@@ -0,0 +1,12 @@
1
+ #Predefined synchronized hash.
2
+ #
3
+ #===Examples
4
+ # h = Tsafe::MonHash.new
5
+ # h['test'] = 'trala'
6
+ # ret = h['test']
7
+ class Tsafe::MonHash < ::Hash
8
+ @@tsafe_rwmutex_w_methods = [:[]=, :clear, :delete, :delete_if, :keep_if, :merge!, :rehash, :reject!, :replace, :select!, :shift, :store, :update, :values_at]
9
+ @@tsafe_rwmutex_r_methods = [:each, :each_key, :each_pair, :each_value]
10
+
11
+ include Tsafe::Mrswlock::SynModule
12
+ end
@@ -0,0 +1,29 @@
1
+ #This module can be included on a class to make all method-calls synchronized (by using monitor). Examples with array and hash are below.
2
+ #
3
+ #===Examples
4
+ # class MySyncedClass < SomeOtherClassThatNeedsToBeSynchronized
5
+ # include Tsafe::Monitored
6
+ # end
7
+ module Tsafe::Monitored
8
+ def self.included(base)
9
+ base.to_s.split("::").inject(Object, :const_get).class_eval do
10
+ self.instance_methods.each do |method_name|
11
+ #These two methods create warnings under JRuby.
12
+ if RUBY_ENGINE == "jruby"
13
+ next if method_name == :instance_exec or method_name == :instance_eval
14
+ end
15
+
16
+ new_method_name = "_ts_#{method_name}"
17
+ alias_method(new_method_name, method_name)
18
+
19
+ define_method method_name do |*args, &block|
20
+ #Need to use monitor, since the internal calls might have to run not-synchronized, and we have just overwritten the internal methods.
21
+ @_ts_mutex = Monitor.new if !@_ts_mutex
22
+ @_ts_mutex.synchronize do
23
+ return self._ts___send__(new_method_name, *args, &block)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,75 @@
1
+ #A class that allows many simultanious read-synchronizations but locks both reading and writing while calling the write-synchronzie-method.
2
+ class Tsafe::Mrswlock
3
+ @@debug = false
4
+
5
+ #Sets various variables.
6
+ def initialize
7
+ @reads = 0
8
+ @w_mutex = Mutex.new
9
+ end
10
+
11
+ #Runs the given block through the read-synchronization.
12
+ def rsync
13
+ begin
14
+ while @w_mutex.locked?
15
+ Thread.pass
16
+ print "Passed because lock.\n" if @@debug
17
+ end
18
+
19
+ @reads += 1
20
+ print "Reading more than one at a time! (#{@reads})\n" if @@debug and @reads >= 2
21
+ yield
22
+ ensure
23
+ @reads -= 1
24
+ end
25
+ end
26
+
27
+ #Runs the given block through the write-synchronization (locks both reading and writing).
28
+ def wsync
29
+ @w_mutex.synchronize do
30
+ #Wait for any reads to finish that might have started while we were getting the lock.
31
+ while @reads > 0
32
+ Thread.pass
33
+ print "Passed because reading.\n" if @@debug
34
+ end
35
+
36
+ yield
37
+ end
38
+ end
39
+
40
+ module SynModule
41
+ def self.included(base)
42
+ base.to_s.split("::").inject(Object, :const_get).class_eval do
43
+ #Rename initialize.
44
+ alias_method(:initialize_rwmutex, :initialize)
45
+
46
+ define_method(:initialize) do |*args, &block|
47
+ @tsafe_rwmutex = Tsafe::Mrswlock.new
48
+ return initialize_rwmutex(*args, &block)
49
+ end
50
+
51
+ base.class_variable_get(:@@tsafe_rwmutex_r_methods).each do |mname|
52
+ newmname = "tsafe_rwmutex_#{mname}".to_sym
53
+ alias_method(newmname, mname)
54
+
55
+ define_method(mname) do |*args, &block|
56
+ @tsafe_rwmutex.rsync do
57
+ return self.__send__(newmname, *args, &block)
58
+ end
59
+ end
60
+ end
61
+
62
+ base.class_variable_get(:@@tsafe_rwmutex_w_methods).each do |mname|
63
+ newmname = "tsafe_rwmutex_#{mname}".to_sym
64
+ alias_method(newmname, mname)
65
+
66
+ define_method(mname) do |*args, &block|
67
+ @tsafe_rwmutex.wsync do
68
+ return self.__send__(newmname, *args, &block)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,29 @@
1
+ #This module can be included on a class to make all method-calls synchronized (by using mutex). Examples with array and hash are below.
2
+ #
3
+ #===Examples
4
+ # class MySyncedClass < SomeOtherClassThatNeedsToBeSynchronized
5
+ # include Tsafe::Mutexed
6
+ # end
7
+ module Tsafe::Mutexed
8
+ def self.included(base)
9
+ base.to_s.split("::").inject(Object, :const_get).class_eval do
10
+ self.instance_methods.each do |method_name|
11
+ #These two methods create warnings under JRuby.
12
+ if RUBY_ENGINE == "jruby"
13
+ next if method_name == :instance_exec or method_name == :instance_eval
14
+ end
15
+
16
+ new_method_name = "_ts_#{method_name}"
17
+ alias_method(new_method_name, method_name)
18
+
19
+ define_method method_name do |*args, &block|
20
+ #Need to use monitor, since the internal calls might have to run not-synchronized, and we have just overwritten the internal methods.
21
+ @_ts_mutex = Mutex.new if !@_ts_mutex
22
+ @_ts_mutex.synchronize do
23
+ return self._ts___send__(new_method_name, *args, &block)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
data/include/proxy.rb ADDED
@@ -0,0 +1,29 @@
1
+ #Instances of this class proxies calls to a given-object by using a mutex or monitor.
2
+ #
3
+ #==== Examples
4
+ # threadsafe_array = Tsafe::Proxy.new(:obj => [])
5
+ # threadsafe_array << 5
6
+ # ret = threadsafe_array[0]
7
+ #
8
+ # threadsafe_array = Tsafe::Proxy.new(:obj => [], :monitor => true)
9
+ class Tsafe::Proxy
10
+ #Spawn needed vars.
11
+ def initialize(args)
12
+ if args[:monitor]
13
+ @mutex = Monitor.new
14
+ elsif args[:mutex]
15
+ @mutex = args[:mutex]
16
+ else
17
+ @mutex = Mutex.new
18
+ end
19
+
20
+ @obj = args[:obj]
21
+ end
22
+
23
+ #Proxies all calls to this object through the mutex.
24
+ def method_missing(method_name, *args, &block)
25
+ @mutex.synchronize do
26
+ @obj.__send__(method_name, *args, &block)
27
+ end
28
+ end
29
+ end
data/lib/tsafe.rb CHANGED
@@ -2,119 +2,16 @@ require "monitor"
2
2
 
3
3
  #This module contains various tools to handle thread-safety easily and pretty.
4
4
  module Tsafe
5
+ #Autoloader for subclasses.
6
+ def self.const_missing(name)
7
+ require "#{File.dirname(__FILE__)}/../include/#{name.to_s.downcase}.rb"
8
+ raise "Still not loaded: '#{name}'." if !Tsafe.const_defined?(name)
9
+ return Tsafe.const_get(name)
10
+ end
11
+
5
12
  #JRuby can corrupt an array in a threadded env. Use this method to only get a synchronized array when running JRuby and not having to write "if RUBY_ENGINE"-stuff.
6
13
  def self.std_array
7
14
  return MonArray.new if RUBY_ENGINE == "jruby"
8
15
  return []
9
16
  end
10
-
11
- #Instances of this class proxies calls to a given-object by using a mutex or monitor.
12
- #
13
- #==== Examples
14
- # threadsafe_array = Tsafe::Proxy.new(:obj => [])
15
- # threadsafe_array << 5
16
- # ret = threadsafe_array[0]
17
- #
18
- # threadsafe_array = Tsafe::Proxy.new(:obj => [], :monitor => true)
19
- class Proxy
20
- #Spawn needed vars.
21
- def initialize(args)
22
- if args[:monitor]
23
- @mutex = Monitor.new
24
- elsif args[:mutex]
25
- @mutex = args[:mutex]
26
- else
27
- @mutex = Mutex.new
28
- end
29
-
30
- @obj = args[:obj]
31
- end
32
-
33
- #Proxies all calls to this object through the mutex.
34
- def method_missing(method_name, *args, &block)
35
- @mutex.synchronize do
36
- @obj.__send__(method_name, *args, &block)
37
- end
38
- end
39
- end
40
-
41
- #This module can be included on a class to make all method-calls synchronized (by using monitor). Examples with array and hash are below.
42
- #
43
- #===Examples
44
- # class MySyncedClass < SomeOtherClassThatNeedsToBeSynchronized
45
- # include Tsafe::Monitored
46
- # end
47
- module Monitored
48
- def self.included(base)
49
- base.to_s.split("::").inject(Object, :const_get).class_eval do
50
- self.instance_methods.each do |method_name|
51
- #These two methods create warnings under JRuby.
52
- if RUBY_ENGINE == "jruby"
53
- next if method_name == :instance_exec or method_name == :instance_eval
54
- end
55
-
56
- new_method_name = "_ts_#{method_name}"
57
- alias_method(new_method_name, method_name)
58
-
59
- define_method method_name do |*args, &block|
60
- #Need to use monitor, since the internal calls might have to run not-synchronized, and we have just overwritten the internal methods.
61
- @_ts_mutex = Monitor.new if !@_ts_mutex
62
- @_ts_mutex.synchronize do
63
- return self._ts___send__(new_method_name, *args, &block)
64
- end
65
- end
66
- end
67
- end
68
- end
69
- end
70
-
71
- #This module can be included on a class to make all method-calls synchronized (by using mutex). Examples with array and hash are below.
72
- #
73
- #===Examples
74
- # class MySyncedClass < SomeOtherClassThatNeedsToBeSynchronized
75
- # include Tsafe::Mutexed
76
- # end
77
- module Mutexed
78
- def self.included(base)
79
- base.to_s.split("::").inject(Object, :const_get).class_eval do
80
- self.instance_methods.each do |method_name|
81
- #These two methods create warnings under JRuby.
82
- if RUBY_ENGINE == "jruby"
83
- next if method_name == :instance_exec or method_name == :instance_eval
84
- end
85
-
86
- new_method_name = "_ts_#{method_name}"
87
- alias_method(new_method_name, method_name)
88
-
89
- define_method method_name do |*args, &block|
90
- #Need to use monitor, since the internal calls might have to run not-synchronized, and we have just overwritten the internal methods.
91
- @_ts_mutex = Mutex.new if !@_ts_mutex
92
- @_ts_mutex.synchronize do
93
- return self._ts___send__(new_method_name, *args, &block)
94
- end
95
- end
96
- end
97
- end
98
- end
99
- end
100
-
101
- #Predefined synchronized array.
102
- #
103
- #===Examples
104
- # arr = Tsafe::MonArray.new
105
- # arr << 5
106
- # ret = arr[0]
107
- class MonArray < ::Array
108
- include Monitored
109
- end
110
-
111
- #Predefined synchronized hash.
112
- #
113
- #===Examples
114
- # h = Tsafe::MonHash.new
115
- # h['test'] = 'trala'
116
- # ret = h['test']
117
- class MonHash < ::Hash
118
- include Monitored
119
- end
120
17
  end
@@ -0,0 +1,83 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Tsafe::Rwmutex" do
4
+ it "should work!" do
5
+ Thread.abort_on_exception = true
6
+ debug = false
7
+
8
+ print "Setting initial values.\n" if debug
9
+ hash = Tsafe::MonHash.new
10
+ 0.upto(15) do |count|
11
+ realcount = 100000000 - count
12
+ hash[realcount] = realcount
13
+ end
14
+
15
+ ts = []
16
+
17
+ 1.upto(20) do |tcount|
18
+ print "Starting thread #{tcount}\n" if debug
19
+ ts << Thread.new do
20
+ 1.upto(10000) do |count|
21
+ hash[count] = count
22
+
23
+ hash[count]
24
+ hash.key?(count)
25
+
26
+ hash.delete(count)
27
+
28
+ hash.each do |key, val|
29
+ #nothing...
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ ts.each do |t|
36
+ print "Joining #{t.__id__}\n" if debug
37
+ t.join
38
+ end
39
+ end
40
+
41
+ it "should work!" do
42
+ debug = false
43
+
44
+ hash = {}
45
+ 0.upto(15) do |count|
46
+ realcount = 100000000 - count
47
+ hash[realcount] = realcount
48
+ end
49
+
50
+ rwm = Tsafe::Mrswlock.new
51
+ ts = []
52
+
53
+ 1.upto(20) do
54
+ ts << Thread.new do
55
+ 1.upto(10000) do |count|
56
+ rwm.wsync do
57
+ hash[count] = count
58
+ end
59
+
60
+ rwm.rsync do
61
+ hash[count]
62
+ hash.key?(count)
63
+ end
64
+
65
+ rwm.wsync do
66
+ hash.delete(count)
67
+ end
68
+
69
+ rwm.rsync do
70
+ hash.each do |key, val|
71
+ #nothing...
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ ts.each do |t|
79
+ print "Joining #{t.__id__}\n" if debug
80
+ t.join
81
+ end
82
+ end
83
+ 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.1"
8
+ s.version = "0.0.2"
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-05-12}
12
+ s.date = %q{2012-07-25}
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 = [
@@ -25,7 +25,14 @@ Gem::Specification.new do |s|
25
25
  "README.rdoc",
26
26
  "Rakefile",
27
27
  "VERSION",
28
+ "include/monarray.rb",
29
+ "include/monhash.rb",
30
+ "include/monitored.rb",
31
+ "include/mrswlock.rb",
32
+ "include/mutexed.rb",
33
+ "include/proxy.rb",
28
34
  "lib/tsafe.rb",
35
+ "spec/mrswlock_spec.rb",
29
36
  "spec/spec_helper.rb",
30
37
  "spec/tsafe_spec.rb",
31
38
  "tsafe.gemspec"
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: tsafe
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
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-05-12 00:00:00 +02:00
13
+ date: 2012-07-25 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -75,7 +75,14 @@ files:
75
75
  - README.rdoc
76
76
  - Rakefile
77
77
  - VERSION
78
+ - include/monarray.rb
79
+ - include/monhash.rb
80
+ - include/monitored.rb
81
+ - include/mrswlock.rb
82
+ - include/mutexed.rb
83
+ - include/proxy.rb
78
84
  - lib/tsafe.rb
85
+ - spec/mrswlock_spec.rb
79
86
  - spec/spec_helper.rb
80
87
  - spec/tsafe_spec.rb
81
88
  - tsafe.gemspec
@@ -93,7 +100,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
100
  requirements:
94
101
  - - ">="
95
102
  - !ruby/object:Gem::Version
96
- hash: 1960429092658754527
103
+ hash: -2173245037077318773
97
104
  segments:
98
105
  - 0
99
106
  version: "0"