tsafe 0.0.4 → 0.0.5

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/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"