A __real__ drb question

now that i've already stuck my foot in my mouth, i'd like to ask a real drb
question.

say you've got a thread accessing an obj which is being served by drb:

   require 'drb/drb'

   mode = ARGV.shift || 'server'

   class Q
     def initialize; @q=; end
     def push obj; @q << obj; end
     def pop; @q.shift; end
   end

   case mode
     when 'server'
       q = Q.new

···

#
# is this safe?
#
       Thread.new{loop{ sleep 2; q.push Time.now }}

       DRb.start_service nil, q
       uri = DRb.uri
       puts "ruby #{ $0 } client #{ DRb.uri }"
       DRb.thread.join

     when 'client'
       uri = ARGV.shift
       DRb.start_service nil, nil
       q = DRbObject.new nil, uri
       loop do
         obj = q.pop
         p obj
         q.push 42
         sleep 0.5
       end
   end

my understanding is that access to the object via DRb is provided by multiple
synchronized threads. eg. only one DRb thread would be accessing your object
at once so you generally don't need to consider thread coordination. in this
case, however, i have a thread outside of DRb accessing the object - what sort
of coordination would this require? perhaps it would be better to have the
thread obtain a DRbObject itself and allow the DRb library to handle all the
coordination?

eg.

....
     when 'server'
       q = Q.new
       DRb.start_service nil, q
       uri = DRb.uri
#
# safe?
#
       q = DRbObject.new nil, uri
       Thread.new{loop{ sleep 2; q.push Time.now }}

       puts "ruby #{ $0 } client #{ DRb.uri }"
       DRb.thread.join
....

comments?

-a
--

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
A flower falls, even though we love it; and a weed grows, even though we do
not love it. --Dogen

===============================================================================

"Ara.T.Howard" <Ara.T.Howard@noaa.gov> schrieb im Newsbeitrag
news:Pine.LNX.4.60.0406100854460.10410@harp.ngdc.noaa.gov...

now that i've already stuck my foot in my mouth, i'd like to ask a real

drb

question.

say you've got a thread accessing an obj which is being served by drb:

   require 'drb/drb'

   mode = ARGV.shift || 'server'

   class Q
     def initialize; @q=; end
     def push obj; @q << obj; end
     def pop; @q.shift; end
   end

   case mode
     when 'server'
       q = Q.new
#
# is this safe?
#
       Thread.new{loop{ sleep 2; q.push Time.now }}

       DRb.start_service nil, q
       uri = DRb.uri
       puts "ruby #{ $0 } client #{ DRb.uri }"
       DRb.thread.join

     when 'client'
       uri = ARGV.shift
       DRb.start_service nil, nil
       q = DRbObject.new nil, uri
       loop do
         obj = q.pop
         p obj
         q.push 42
         sleep 0.5
       end
   end

my understanding is that access to the object via DRb is provided by

multiple

synchronized threads. eg. only one DRb thread would be accessing your

object

at once so you generally don't need to consider thread coordination.

That was not my understanding and tests seem to back this:

in this
case, however, i have a thread outside of DRb accessing the object - what

sort

of coordination would this require? perhaps it would be better to have

the

thread obtain a DRbObject itself and allow the DRb library to handle all

the

coordination?

A general note about concurrency that applies here as well: Typically
"automated" synchronization is not done because no automated mechanism can
know the granularity of concurrency needed. You might even access an
instance concurrently in a proper way without synchronization (e.g. if the
instance does not contain any state itself). Another example is a set of
operations that has to be done exclusively; a typical example is check for
presence and then

···

eg.

...
     when 'server'
       q = Q.new
       DRb.start_service nil, q
       uri = DRb.uri
#
# safe?
#
       q = DRbObject.new nil, uri
       Thread.new{loop{ sleep 2; q.push Time.now }}

       puts "ruby #{ $0 } client #{ DRb.uri }"
       DRb.thread.join
...

comments?

-a
--

============================================================================

> EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
> PHONE :: 303.497.6469
> A flower falls, even though we love it; and a weed grows, even though we

do

> not love it. --Dogen

============================================================================

*** forget the other posting, I accidentally hit 'send' ***

"Ara.T.Howard" <Ara.T.Howard@noaa.gov> schrieb im Newsbeitrag
news:Pine.LNX.4.60.0406100854460.10410@harp.ngdc.noaa.gov...

now that i've already stuck my foot in my mouth, i'd like to ask a real

drb

question.

say you've got a thread accessing an obj which is being served by drb:

   require 'drb/drb'

   mode = ARGV.shift || 'server'

   class Q
     def initialize; @q=; end
     def push obj; @q << obj; end
     def pop; @q.shift; end
   end

   case mode
     when 'server'
       q = Q.new
#
# is this safe?
#

No.

       Thread.new{loop{ sleep 2; q.push Time.now }}

       DRb.start_service nil, q
       uri = DRb.uri
       puts "ruby #{ $0 } client #{ DRb.uri }"
       DRb.thread.join

     when 'client'
       uri = ARGV.shift
       DRb.start_service nil, nil
       q = DRbObject.new nil, uri
       loop do
         obj = q.pop
         p obj
         q.push 42
         sleep 0.5
       end
   end

my understanding is that access to the object via DRb is provided by

multiple

synchronized threads. eg. only one DRb thread would be accessing your

object

at once so you generally don't need to consider thread coordination.

That was not my understanding and tests back this notion:

DRB started at druby://localhost:8787
#<Thread:0x101d6d88 run>: #<Foo:0x101d7058>: ++++ [0]
#<Thread:0x101d6ae8 run>: #<Foo:0x101d7058>: ++++ [0]
#<Thread:0x101d6848 run>: #<Foo:0x101d7058>: ++++ [0]
#<Thread:0x101d65a8 run>: #<Foo:0x101d7058>: ++++ [0]
#<Thread:0x101d5888 run>: #<Foo:0x101d7058>: ++++ [0]
#<Thread:0x101d6d88 run>: #<Foo:0x101d7058>: ---- [0]
#<Thread:0x101d6d88 run>: #<Foo:0x101d7058>: ++++ [1]
#<Thread:0x101d6848 run>: #<Foo:0x101d7058>: ---- [0]
#<Thread:0x101d65a8 run>: #<Foo:0x101d7058>: ---- [0]
#<Thread:0x101d6848 run>: #<Foo:0x101d7058>: ++++ [1]
#<Thread:0x101d65a8 run>: #<Foo:0x101d7058>: ++++ [1]
#<Thread:0x101d6ae8 run>: #<Foo:0x101d7058>: ---- [0]
#<Thread:0x101d6ae8 run>: #<Foo:0x101d7058>: ++++ [1]
#<Thread:0x101d6d88 run>: #<Foo:0x101d7058>: ---- [1]
#<Thread:0x101d6d88 run>: #<Foo:0x101d7058>: ++++ [2]
#<Thread:0x101d65a8 run>: #<Foo:0x101d7058>: ---- [1]
....

(server output, see code attached)

in this
case, however, i have a thread outside of DRb accessing the object - what

sort

of coordination would this require? perhaps it would be better to have

the

thread obtain a DRbObject itself and allow the DRb library to handle all

the

coordination?

A general note about concurrency that applies here as well: Typically
"automated" synchronization is not done because no automated mechanism can
know the granularity of concurrency needed. You might even access an
instance concurrently in a proper way without synchronization (e.g. if the
instance does not contain any state itself). Another case is a set of
operations that has to be done exclusively; a typical example is check for
presence of something and then act depending on the presence like in:

mutex.synchronize do
  if foo.has_data?
    puts foo.get_data
  else
    foo.set_data "something"
  end
end

That's why typically no synchronization is done automatically.

Kind regards

    robert

Did I say I included the source code? Darn...

    robert

#!/usr/bin/ruby

require 'drb/drb'

URI="druby://localhost:8787"

module Kernel
  private

  def tputs(*a)
    th = Thread.current.inspect

    a.each do |arg|
      puts "#{th}: #{a}"
    end
  end
end

class Foo
  def test(*a)
    tputs "#{self.inspect}: ++++ #{a.inspect}"
    sleep( 1 + rand( 3 ) )
    Thread.pass
    tputs "#{self.inspect}: ---- #{a.inspect}"
  end
end

mode = ARGV.shift || 'server'
time = ARGV.shift || 60

case mode
  when 'server'
    obj = Foo.new

    drb = DRb.start_service URI, obj
    puts "DRB started at #{URI}"
    sleep time
    puts "Stopping DRB..."
    drb.stop_service
    DRb.thread.join
    puts "DRB terminated"

  when 'client'
    # a single client
    DRb.start_service
    obj = DRbObject.new_with_uri(URI)

    10.times do |i|
      puts i
      obj.test i
    end

  when 'multi'
    # multiple clients
    DRb.start_service
    threads = []

    5.times do |th|
      threads << Thread.new(th) do |id|
        o = DRbObject.new_with_uri(URI)

        5.times do |i|
          puts "client #{id}: #{i}"
          o.test i
        end
      end
    end

    threads.each {|t| t.join}
end