Synchronized Circular Buffer

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?}
element = nil
synchronize do
element = @elements[@front]
@elements[@front] = nil
@front = (@front + 1) % @capacity
@full_cond.signal
end
return element
end

def put(element)
@full_cond.wait_while {full?}
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
end

def empty?
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’

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.

Sam D.

Hi Robert,

Thanks for the help, it works perfectly now. I see that I should treat
the synchronised block as wrapping the entire method body, just as the
synchronise keyword would in Java. Makes sense :slight_smile:

Is it possible to subscribe to this forum via RSS (or another method)?
Looking forward to the day when I’ve improved enough to help others.

Regards,

Sam

2010/7/1 Sam D. [email protected]:

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.

      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. :slight_smile:

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).

workers[i] = Worker.new(buffer)
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

2010/7/1 Sam D. [email protected]:

Thanks for the help, it works perfectly now. I see that I should treat
the synchronised block as wrapping the entire method body, just as the
synchronise keyword would in Java. Makes sense :slight_smile:

Not necessarily. The synchronized block must be only as long as
necessary to guard the critical section. I’d rather say, it’s bad to
always synchronize complete methods.

Is it possible to subscribe to this forum via RSS (or another method)?

There is news:comp.lang.ruby and ruby-talk mailing list - all are
mirrored full duplex (see [1]).

Looking forward to the day when I’ve improved enough to help others.

The day will come - inevitably. :slight_smile:

Kind regards

robert

[1] Mailing Lists