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 Dalton

···

--
Posted via http://www.ruby-forum.com/.

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

  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

···

2010/7/1 Sam Dalton <mail@samdalton.co.nz>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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

···

--
Posted via http://www.ruby-forum.com/.

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

···

2010/7/1 Sam Dalton <mail@samdalton.co.nz>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/