From: "Hal E. Fulton" Date: 2001-03-16T17:18:21+09:00 Subject: [ruby-talk:12731] Fw: (My) Thread bug - sync != lock/unlock Hello all... While my ISP had major mail server problems (statewide) I tried to post this... not sure if it went through. If it did, I never got it back and never saw a response... In a nutshell: Mutex#synchronize is supposed to be the same as Mutex#lock followed by Mutex#unlock... I've got a bit of code that works the latter way and fails the former way. "Curiouser and curiouser," said Alice. Ideas, anyone? Hal Fulton ----- Original Message ----- From: Hal E. Fulton To: Sent: Tuesday, March 06, 2001 1:27 AM Subject: (My) Thread bug - sync != lock/unlock > Hello all, > > I recently made an "improvement" to a little piece of code... > and it quit working. (I call that "rebugging." Yeah, YOU'VE > never done it. Right...) > > I really thought this code was correct... I was implementing > a protected queue for a simple producer-consumer problem. > (Yes, I know about the existing one. This was an exercise.) > I used a mutex and a pair of condition variables. At least, > that's what I meant to do. > > Everything works fine in the code as shown. I even added a > little extra delay to the consumer so the queue would get > "fuller" -- that worked fine. > > But when I replace the lock/unlock sequences with a block > passed to mutex.synchronize, it doesn't work anymore! > > What have I done wrong? > > Thanks much, > Hal Fulton > > =========================== > require "thread" > > class ProtectedBuffer > > def initialize(n) > @max = n > @buff = [] > @mutex = Mutex.new > @notFull = ConditionVariable.new > @notEmpty = ConditionVariable.new > end > > def enqueue x > @mutex.lock > while self.full? do > @notFull.wait(@mutex) > end > @buff.push x > @notEmpty.signal > @mutex.unlock > end > > def dequeue > @mutex.lock > while self.empty? do > @notEmpty.wait(@mutex) > end > x = @buff.shift > @notFull.signal > @mutex.unlock > return x > end > > def empty? > @buff.size == 0 > end > > def full? > @buff.size == @max > end > > def size > @buff.size > end > > end > > > # Main... > > > buffer = ProtectedBuffer.new(10) > > > producer = Thread.new do > item = 0 > loop do > sleep rand 0 > puts "Producer makes #{item}" > buffer.enqueue item > item += 1 > end > end > > consumer = Thread.new do > loop do > sleep (rand 0)+0.3 > item = buffer.dequeue > puts "Consumer retrieves #{item}" > end > end > > > sleep 60 # Run a minute, then die and kill threads > > >