Skip to content

Commit

Permalink
Modified read-write lock code so readers and writers will interleave
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdowad committed Feb 21, 2012
1 parent 1a66925 commit e09a798
Showing 1 changed file with 21 additions and 5 deletions.
26 changes: 21 additions & 5 deletions ruby-threads/read_write_lock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,26 @@ def acquire_read_lock
c = @counter.value
raise "Too many reader threads!" if (c & MAX_READERS) == MAX_READERS

# If a writer is running OR waiting, we need to wait
# If a writer is waiting when we first queue up, we need to wait
if c >= WAITING_WRITER
# But it is possible that the writer could finish and decrement @counter right here...
@reader_mutex.synchronize do
# So check again inside the synchronized section
@reader_q.wait(@reader_mutex) if @counter.value >= WAITING_WRITER
end

# after a reader has waited once, they are allowed to "barge" ahead of waiting writers
# but if a writer is *running*, the reader still needs to wait (naturally)
while(true)
c = @counter.value
if c >= RUNNING_WRITER
@reader_mutex.synchronize do
@reader_q.wait(@reader_mutex) if @counter.value >= RUNNING_WRITER
end
else
return if @counter.compare_and_swap(c,c+1)
end
end
else
break if @counter.compare_and_swap(c,c+1)
end
Expand Down Expand Up @@ -112,7 +125,9 @@ def acquire_write_lock
# Then we are OK to stop waiting and go ahead
# Otherwise go back and wait again
c = @counter.value
break if (c < RUNNING_WRITER) && @counter.compare_and_swap(c,c+RUNNING_WRITER-WAITING_WRITER)
break if (c < RUNNING_WRITER) &&
((c & MAX_READERS) == 0) &&
@counter.compare_and_swap(c,c+RUNNING_WRITER-WAITING_WRITER)
end
break
end
Expand All @@ -123,10 +138,9 @@ def release_write_lock
while(true)
c = @counter.value
if @counter.compare_and_swap(c,c-RUNNING_WRITER)
@reader_mutex.synchronize { @reader_q.broadcast }
if (c & MAX_WRITERS) > 0 # if any writers are waiting...
@writer_mutex.synchronize { @writer_q.signal }
else
@reader_mutex.synchronize { @reader_q.broadcast }
end
break
end
Expand Down Expand Up @@ -170,7 +184,7 @@ def with_read_lock

require 'benchmark'

TOTAL_THREADS = 40
TOTAL_THREADS = 12

def test(lock)
puts "READ INTENSIVE (80% read, 20% write):"
Expand All @@ -192,6 +206,7 @@ def single_test(lock, n_readers, n_writers, reader_iterations=50, writer_iterati
Thread.new do
reader_iterations.times do
lock.with_read_lock do
print "r"
mutex.synchronize { bad = true } if (data % 2) != 0
sleep(reader_sleep)
mutex.synchronize { bad = true } if (data % 2) != 0
Expand All @@ -203,6 +218,7 @@ def single_test(lock, n_readers, n_writers, reader_iterations=50, writer_iterati
Thread.new do
writer_iterations.times do
lock.with_write_lock do
print "w"
# invariant: other threads should NEVER see "data" as an odd number
value = (data += 1)
# if a reader runs right now, this invariant will be violated
Expand Down

0 comments on commit e09a798

Please sign in to comment.