tsafe 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.5
data/lib/tsafe.rb CHANGED
@@ -4,7 +4,7 @@ require "monitor"
4
4
  module Tsafe
5
5
  #Autoloader for subclasses.
6
6
  def self.const_missing(name)
7
- require "#{File.dirname(__FILE__)}/../include/#{name.to_s.downcase}.rb"
7
+ require "#{File.dirname(__FILE__)}/tsafe_#{name.to_s.downcase}.rb"
8
8
  raise "Still not loaded: '#{name}'." if !Tsafe.const_defined?(name)
9
9
  return Tsafe.const_get(name)
10
10
  end
File without changes
File without changes
File without changes
@@ -6,20 +6,30 @@ class Tsafe::Mrswlock
6
6
  def initialize
7
7
  @reads = 0
8
8
  @w_mutex = Mutex.new
9
+
10
+ #This variable is used to allow reads from the writing thread (monitor-behavior).
11
+ @locked_by = nil
12
+
13
+ #This hash holds thread-IDs for threads that are reading.
14
+ @reading_threads = {}
9
15
  end
10
16
 
11
17
  # Runs the given block through the read-synchronization.
12
18
  def rsync
13
19
  begin
14
- while @w_mutex.locked?
20
+ tid = Thread.current.__id__
21
+
22
+ while @w_mutex.locked? and @locked_by != tid
15
23
  Thread.pass
16
24
  print "Passed because lock.\n" if @@debug
17
25
  end
18
26
 
27
+ @reading_threads[tid] = true
19
28
  @reads += 1
20
29
  print "Reading more than one at a time! (#{@reads})\n" if @@debug and @reads >= 2
21
30
  yield
22
31
  ensure
32
+ @reading_threads.delete(tid)
23
33
  @reads -= 1
24
34
  end
25
35
  end
@@ -31,13 +41,25 @@ class Tsafe::Mrswlock
31
41
  # end
32
42
  def wsync
33
43
  @w_mutex.synchronize do
34
- #Wait for any reads to finish that might have started while we were getting the lock.
35
- while @reads > 0
36
- Thread.pass
37
- print "Passed because reading.\n" if @@debug
44
+ begin
45
+ tid = Thread.current.__id__
46
+ @locked_by = tid
47
+
48
+ #Wait for any reads to finish that might have started while we were getting the lock.
49
+ #Also allow write if there is only one reading thread and that reading thread is the current thread.
50
+ while @reads > 0
51
+ if @reading_threads.key?(tid)
52
+ raise ThreadError, "Deadlock: Writing is not allowed while reading."
53
+ end
54
+
55
+ Thread.pass
56
+ print "Passed because reading.\n" if @@debug
57
+ end
58
+
59
+ yield
60
+ ensure
61
+ @locked_by = nil
38
62
  end
39
-
40
- yield
41
63
  end
42
64
  end
43
65
 
File without changes
File without changes
@@ -1,7 +1,9 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
+ require "timeout"
4
+
3
5
  describe "Tsafe::Rwmutex" do
4
- it "should work!" do
6
+ it "should work with the modified hash" do
5
7
  Thread.abort_on_exception = true
6
8
  debug = false
7
9
 
@@ -22,10 +24,10 @@ describe "Tsafe::Rwmutex" do
22
24
 
23
25
  ts = []
24
26
 
25
- 1.upto(20) do |tcount|
27
+ 1.upto(10) do |tcount|
26
28
  print "Starting thread #{tcount}\n" if debug
27
29
  ts << Thread.new do
28
- 1.upto(10000) do |count|
30
+ 1.upto(5000) do |count|
29
31
  hash[count] = count
30
32
 
31
33
  hash[count]
@@ -46,7 +48,7 @@ describe "Tsafe::Rwmutex" do
46
48
  end
47
49
  end
48
50
 
49
- it "should work!" do
51
+ it "should work with manual lock creation" do
50
52
  debug = false
51
53
 
52
54
  hash = {}
@@ -58,9 +60,9 @@ describe "Tsafe::Rwmutex" do
58
60
  rwm = Tsafe::Mrswlock.new
59
61
  ts = []
60
62
 
61
- 1.upto(20) do
63
+ 1.upto(10) do
62
64
  ts << Thread.new do
63
- 1.upto(10000) do |count|
65
+ 1.upto(5000) do |count|
64
66
  rwm.wsync do
65
67
  hash[count] = count
66
68
  end
@@ -88,4 +90,51 @@ describe "Tsafe::Rwmutex" do
88
90
  t.join
89
91
  end
90
92
  end
93
+
94
+ it "should be able to read while writing from same thread while other threads are stressing" do
95
+ hash = Tsafe::MonHash.new
96
+ 0.upto(1000) do |count|
97
+ hash[count] = count
98
+ end
99
+
100
+ Timeout.timeout(7) do
101
+ ts = []
102
+ 1.upto(5) do
103
+ ts << Thread.new do
104
+ hash.keep_if do |key, val|
105
+ hash.each do |key2, val2|
106
+ #ignore.
107
+ end
108
+
109
+ if key > 500
110
+ true
111
+ else
112
+ false
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ ts.each do |t|
119
+ t.join
120
+ end
121
+ end
122
+ end
123
+
124
+ it "should not be able to write while reading from same thread" do
125
+ hash = Tsafe::MonHash.new
126
+ 0.upto(1000) do |count|
127
+ hash[count] = count
128
+ end
129
+
130
+ begin
131
+ hash.each do |key, val|
132
+ hash.delete(key)
133
+ end
134
+
135
+ raise "Expected ThreadError but didnt get raised."
136
+ rescue ThreadError
137
+ #ignore - supposed to happen.
138
+ end
139
+ end
91
140
  end
data/tsafe.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{tsafe}
8
- s.version = "0.0.4"
8
+ s.version = "0.0.5"
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"]
@@ -25,13 +25,13 @@ 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",
34
28
  "lib/tsafe.rb",
29
+ "lib/tsafe_monarray.rb",
30
+ "lib/tsafe_monhash.rb",
31
+ "lib/tsafe_monitored.rb",
32
+ "lib/tsafe_mrswlock.rb",
33
+ "lib/tsafe_mutexed.rb",
34
+ "lib/tsafe_proxy.rb",
35
35
  "spec/mrswlock_spec.rb",
36
36
  "spec/spec_helper.rb",
37
37
  "spec/tsafe_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.4
5
+ version: 0.0.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Kasper Johansen
@@ -75,13 +75,13 @@ 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
84
78
  - lib/tsafe.rb
79
+ - lib/tsafe_monarray.rb
80
+ - lib/tsafe_monhash.rb
81
+ - lib/tsafe_monitored.rb
82
+ - lib/tsafe_mrswlock.rb
83
+ - lib/tsafe_mutexed.rb
84
+ - lib/tsafe_proxy.rb
85
85
  - spec/mrswlock_spec.rb
86
86
  - spec/spec_helper.rb
87
87
  - spec/tsafe_spec.rb
@@ -100,7 +100,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- hash: 2392481904128949132
103
+ hash: -2179111406446538403
104
104
  segments:
105
105
  - 0
106
106
  version: "0"