[#4766] Wiki — "Glen Stampoultzis" <trinexus@...>

21 messages 2000/09/04
[#4768] RE: Wiki — "NAKAMURA, Hiroshi" <nahi@...> 2000/09/04

Hi, Glen,

[#4783] Re: Wiki — Masatoshi SEKI <m_seki@...> 2000/09/04

[#4785] Re: Wiki — "NAKAMURA, Hiroshi" <nakahiro@...> 2000/09/05

Howdy,

[#4883] Re-binding a block — Dave Thomas <Dave@...>

16 messages 2000/09/12

[#4930] Perl 6 rumblings -- RFC 225 (v1) Data: Superpositions — Conrad Schneiker <schneik@...>

Hi,

11 messages 2000/09/15

[#4936] Ruby Book Eng. translation editor's questions — Jon Babcock <jon@...>

20 messages 2000/09/16

[#5045] Proposal: Add constants to Math — Robert Feldt <feldt@...>

15 messages 2000/09/21

[#5077] Crazy idea? infix method calls — hal9000@...

This is a generalization of the "in" operator idea which I

17 messages 2000/09/22

[#5157] Compile Problem with 1.6.1 — Scott Billings <aerogems@...>

When I try to compile Ruby 1.6.1, I get the following error:

15 messages 2000/09/27

[ruby-talk:4997] [RRFC] semaphore class

From: hipster <hipster@...4all.nl>
Date: 2000-09-18 19:25:26 UTC
List: ruby-talk #4997
This might be a nice addition to the Ruby synchronisation primitives.
I welcome comments and improvements.

(shamelessly glarked and adapted from thread.rb)

---8<---
#!/usr/bin/ruby -w

class Semaphore
  def initialize max = 1, init = max
    fail ArgumentError, "maximum value must be > 0" unless max > 0
    fail ArgumentError, "initial value must be >= 0" unless init >= 0
    fail ArgumentError, "initial value must be <= maximum" unless init <= max
    @waiting = []
    @maximum = max
    @value = init
  end

  def signal
    return if @value == @maximum
    Thread.critical = true
    @value += 1
    begin
      t = @waiting.shift
      t.run if t
    rescue ThreadError
      # nothing: tried to run a dead thread
    end
    Thread.critical = false
    self
  end

  def wait
    while(Thread.critical = true; @value == 0)
      @waiting.push Thread.current
      Thread.stop # implies Thread.critical = false
    end
    @value -= 1
    Thread.critical = false
    self
  end

  def synchronize
    wait
    begin
      yield
    ensure
      signal
    end
  end
end


##########################################################################
if __FILE__ == $0

srand
def snooze
  sleep rand 0
end

class Test1
  def initialize
    puts "* N processes contending for M resources, where N > M"
    threads = []
    @sem = Semaphore.new 3      # 3 resources available

    for i in 0..9 do
      threads.push Thread.start{ client i }
    end

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

  def client i
    puts "client #{i}: wait"
    @sem.wait
    puts "client #{i}: running"
    snooze
    puts "client #{i}: signal"
    @sem.signal
  end
end

class Test2
  def initialize
    puts "* synchronous producer/consumer"
    threads = []
    @sin  = Semaphore.new 1, 0
    @sout = Semaphore.new 1, 0
    @shared = 0
    @N = 10

    threads.push Thread.start{ producer }
    threads.push Thread.start{ consumer }
    threads.each{ |t| t.join }
  end

  def producer
    for i in 1..@N do
      snooze
      @shared = i
      puts "produced #{i}"
      @sin.signal
      @sout.wait
    end
  end

  def consumer
    for i in 1..@N do
      snooze
      @sin.wait
      puts "consumed #{@shared}"
      @sout.signal
    end
  end
end

class Test3
  def initialize
    puts "* asynchronous producer/consumer with finite (circular) buffer"
    threads = []
    @MAX = 3
    @buffer = Array.new @MAX, 0
    @input = 0
    @output = 0
    @elements = Semaphore.new @MAX, 0
    @spaces   = Semaphore.new @MAX
    @N = 10

    threads.push Thread.start{ producer }
    threads.push Thread.start{ consumer }
    threads.each{ |t| t.join }
  end

  def producer
    for i in 1..@N do
      snooze
      @spaces.wait
      @buffer[@input] = i
      @input = (@input + 1) % @MAX
      puts "produced #{i}"
      @elements.signal
    end
  end

  def consumer
    for i in 1..@N do
      snooze
      @elements.wait
      n = @buffer[@output]
      @output = (@output + 1) % @MAX
      puts "consumed #{n}"
      @spaces.signal
    end
  end
end

class Test4
  def initialize
    puts "* transfer of control (coroutines)"
    threads = []
    @a = Semaphore.new 1, 0
    @b = Semaphore.new 1, 0
    @c = Semaphore.new 1, 0
    threads.push Thread.new{ parent }
    threads.push Thread.new{ process_a }
    threads.push Thread.new{ process_b }
    threads.each{ |t| t.join }
  end

  def parent
    puts "P: 1"
    @a.signal
    @c.wait
    puts "P: 6"
  end

  def process_a
    @a.wait
    puts "A: 2"
    @b.signal
    @a.wait
    puts "A: 4"
    @b.signal
  end

  def process_b
    @b.wait
    puts "B: 3"
    @a.signal
    @b.wait
    puts "B: 5"
    @c.signal
  end
end

Test1.new
Test2.new
Test3.new
Test4.new

end
---8<---

regards,
Michel

In This Thread

Prev Next