lib/tsafe_mrswlock.rb in tsafe-0.0.10 vs lib/tsafe_mrswlock.rb in tsafe-0.0.11
- old
+ new
@@ -4,10 +4,11 @@
class Tsafe::Mrswlock
# Sets various variables.
def initialize
@reads = 0
@w_mutex = Mutex.new
+ @threads_read_stopped = []
#This variable is used to allow reads from the writing thread (monitor-behavior).
@locked_by = nil
#This hash holds thread-IDs for threads that are reading.
@@ -15,41 +16,61 @@
end
# Runs the given block through the read-synchronization.
def rsync
begin
- tid = Thread.current.__id__
- Thread.pass while @w_mutex.locked? and @locked_by != tid
- @reading_threads[tid] = true
- @reads += 1
- yield
+ begin
+ tid = Thread.current.__id__
+
+ while @w_mutex.locked? and @locked_by != tid
+ @threads_read_stopped << Thread.current
+ Thread.stop
+ end
+
+ @threads_read_stopped.delete(Thread.current)
+ @reading_threads[tid] = true
+ @reads += 1
+ yield
+ ensure
+ @reading_threads.delete(tid)
+ @reads -= 1
+ end
ensure
- @reading_threads.delete(tid)
- @reads -= 1
+ #Restart stopped writing-thread.
+ @threads_write_stopped.run if @threads_write_stopped and @reads <= 0
end
end
#Runs the given block through the write-synchronization (locks both reading and writing).
#===Examples
# lock.wsync do
# #do something within lock.
# end
def wsync
- @w_mutex.synchronize do
- begin
- tid = Thread.current.__id__
- @locked_by = tid
-
- #Wait for any reads to finish that might have started while we were getting the lock.
- #Also allow write if there is only one reading thread and that reading thread is the current thread.
- while @reads > 0
- raise ThreadError, "Deadlock: Writing is not allowed while reading." if @reading_threads.key?(tid)
- Thread.pass
+ begin
+ @w_mutex.synchronize do
+ begin
+ tid = Thread.current.__id__
+ @locked_by = tid
+
+ #Wait for any reads to finish that might have started while we were getting the lock.
+ #Also allow write if there is only one reading thread and that reading thread is the current thread.
+ while @reads > 0
+ raise ThreadError, "Deadlock: Writing is not allowed while reading." if @reading_threads.key?(tid)
+ @threads_write_stopped = Thread.current
+ Thread.stop
+ end
+
+ yield
+ ensure
+ @locked_by = nil
+ @threads_write_stopped = nil
end
-
- yield
- ensure
- @locked_by = nil
+ end
+ ensure
+ #Restart any stopped reading-threads.
+ while thread = @threads_read_stopped.shift
+ thread.run
end
end
end
end
\ No newline at end of file