From: Robert Klemme Date: 2010-07-01T18:10:58+09:00 Subject: Re: Synchronized Circular Buffer 2010/7/1 Sam Dalton : > I'm relatively new to Ruby, having switched from a PHP and Java > background, and I'm having some trouble with the Monitor class trying to > implement a synchronised circular buffer. The other posts here on > synchronised methods aren't quite relevant enough unfortunately. > > My current implementation is the following > > require 'monitor' > > class SynchronisedBuffer < Monitor > >   def initialize(capacity) >      @capacity = capacity >      @front = 0 >      @back = 0 >      @elements = Array.new(capacity) >      @empty_cond = new_cond >      @full_cond = new_cond >      super() >   end > >   def get >       @empty_cond.wait_while {empty?} The line above must be moved into the synchronized block. >       element = nil No need for this. >       synchronize do >           element = @elements[@front] >           @elements[@front] = nil >           @front = (@front + 1) % @capacity >           @full_cond.signal >        end Just move the next line into the block. >        return element >   end > >   def put(element) >       @full_cond.wait_while {full?} The line above must be moved down 1 line. >       synchronize do >           @elements[@back] = element >           @back = (@back + 1) % @capacity >           @empty_cond.signal >        end >   end > >   def full? >       result = false >       synchronize do >           result = (@front == @back and @elements[@front] != nil) >        end >        return result This is sufficient: def full? synchronize do (@front == @back and @elements[@front] != nil) end end >   end > >   def empty? Same as above - saves you some typing. :-) >       result = false >       synchronize do >           result = (@front == @back and @elements[@front] == nil) >        end >        return result >   end > > end > > This has been adapted from a version I had written in Java. The problem > is that when I have a thread call 'get' on the buffer, I receive a > ThreadException saying 'current thread not owner' You need to be holding the lock when waiting on a condition variable (same story in Java btw). > This is being thrown by mon_check_owner, and a bit of poking around > shows that it fails because mon_owner is set to nil in the condition > '@mon_owner != Thread.current'. > > I am using the buffer for a simple producer/consumer web server, like so > > buffer = SynchronisedBuffer.new(10) > workers = [] > > for i in (1..10) >   workers[i] = Worker.new(buffer) > end > > while socket = server.accept >    buffer.put(socket) > end > > I'm writing this purely to gain a better understanding of some important > ruby classes like thread, monitor and socket, and am aware that there > are other ruby web servers I could use straight away :). I'm also trying > to understand the 'ruby way' of coding, so any comments as to how the > above code might better be written would be really appreciated. That's usually a good thing to do. I do it myself all the time. Nothing beats one's own experience. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/