# Ruby 1.9, threads and FreeBSD 5

**URL:** <https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662>\
**Category:** Ruby\
**Created:** [February 20, 2008, 2:12pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662 "2008-02-20T14:12:29Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 2:12pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/1 "2008-02-20T14:12:29Z")

</div>

Hi,

Considering the following theory code:

require “thread”

ping = ConditionVariable.new  
pong = ConditionVariable.new  
mutex = Mutex.new

1.upto(10) do # 10 threads pong  
Thread.new do  
mutex.synchronize do  
ping.wait(mutex)  
puts(“Pong…”)  
pong.signal  
end  
end  
end

1.upto(10) do # 10 threads ping  
Thread.new do  
mutex.synchronize do  
pong.wait(mutex)  
puts(“Ping…”)  
ping.signal  
end  
end  
end

pong.signal # Go!

Thread.list.each { |t| t.join if t != Thread.main }

This code works as expected with Ruby 1.8 on FreeBSD and OS X :

% /usr/bin/ruby ping\_pong\_cond.rb  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…  
Ping…Pong…

But it blocks with Ruby 1.9 on both OS :

% ruby ping\_pong\_cond.rb  
^Cping\_pong\_cond.rb:30:in `join': Interrupt from ping_pong_cond.rb:30:in`block in ’  
from ping\_pong\_cond.rb:30:in `each' from ping_pong_cond.rb:30:in`’

Furthermore, it works fine with Ruby 1.9 on Vista.

As i know there is some change in Ruby threads/Native threads between  
1.8 and 1.9, i suspect this change could be the culprit…

Any clue?

Thanks

---

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 2:26pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/2 "2008-02-20T14:26:37Z")

</div>

> > > > > “E” == Eric J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

Try to add

E\> end

sleep 1

E\> pong.signal # Go!

Guy Decoux

---

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 7:34pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/3 "2008-02-20T19:34:34Z")

</div>

On Wed, 20 Feb 2008 22:09:59 +0900, Eric J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> pong.signal # Go!  
> Your code is buggy: there is a race condition such that the initial  
> #signal  
> can get called before any corresponding #waits. That it superficially  
> appeared  
> to work consistently with 1.8 was an accident of thread scheduling.  
> Adding  
> a ‘sleep’ beforehand, as another poster suggested, makes it more likely  
> to  
> work but does not actually fix the bug.

The correct approach is to use a synchronization primitive which queues  
notifications, for example a semaphore or a queue, rather than a  
condition  
variable. A queued notification can’t get “missed” like this.

-mental

---

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 8:11pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/4 "2008-02-20T20:11:28Z")

</div>

On Thu, 21 Feb 2008 03:33:23 +0900, MenTaLguY [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> The correct approach is to use a synchronization primitive which queues  
> notifications, for example a semaphore or a queue, rather than a condition  
> variable. A queued notification can’t get “missed” like this.

Specifically, if “Foo::Semaphore” were a counted semaphore class:

ping = Foo::Semaphore.new(0)  
pong = Foo::Semaphore.new(0)

def event(wait, notify, message)  
wait.down  
puts message  
notify.up  
end

threads = (1…10).map {  
[ Thread.new { event(pong, ping, “Ping…”) },  
Thread.new { event(ping, pong, “Pong…”) } ]  
}.flatten

pong.up

threads.each { |t| t.join }

Unfortunately there aren’t any good 1.9/JRuby-friendly semaphore  
implementations yet. Here is a very simple portable one (public  
domain):

require ‘thread’

class PortableSemaphore  
def initialize(count=0)  
@lock = Mutex.new  
@nonzero = ConditionVariable.new  
@count = count  
end

def down  
@lock.synchronize do  
@nonzero.wait @lock until @count.nonzero?  
@count -= 1  
end  
self  
end

def up  
@lock.synchronize do  
@count += 1  
@nonzero.signal  
end  
self  
end  
end

Note that this is how condition variables are intended to be used –  
not directly, but as building blocks for more useful primitives.

-mental

---

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 10:37pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/5 "2008-02-20T22:37:13Z")

</div>

On Thu, 21 Feb 2008 05:59:57 +0900, Eric J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Thanks to Guy for the sleep trick and for your PortableSemaphore  
> implementation: i’m gonna investigate it further.

Please note that you shouldn’t ever use the sleep trick in  
production code – it merely hides problems during testing  
when they can still occur under production load.

(I emphasize this, because the sleep trick seems to be fairly  
popular as an “easy fix”; even I’m guilty of using it a lot  
in the past…)

-mental

---

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 10:01pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/6 "2008-02-20T22:01:03Z")

</div>

MenTaLguY [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> Your code is buggy: there is a race condition such that the initial #signal  
> can get called before any corresponding #waits.

Gosh… you’re right.

Thanks to Guy for the sleep trick and for your PortableSemaphore  
implementation: i’m gonna investigate it further.

---

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 11:45pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/7 "2008-02-20T23:45:29Z")

</div>

On Thu, 21 Feb 2008 06:51:18 +0900, Eric J.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I’ve had wrote a general semaphore implementation using IO.pipe

That can still be useful sometimes – for example, I wrote a  
concurrent-selectable gem which provides latch, semaphore, and  
channel (queue) implementations which can be passed as arguments to  
IO.select, libev, etc. because they use IO.pipe underneath.

> PortableSemaphore is way more elegant… thanks a lot (i just wonder  
> if #up/#down honor the FIFO policy)

It depends upon the implementation of ConditionVariable#wait. Some  
Ruby implementations will wake threads in the order the threads called  
#wait, and some will not. Most are roughly FIFO but not 100% “fair”.

Fairness actually involves a tradeoff: while unfair blocking  
primitives can sometimes lead to starvation (as sufficiently  
greedy threads could keep “jumping the queue”), fair primitives  
are more likely to have problems with convoying[1].

-mental

[1] Google “lock convoying”

---

<div class="post-metadata">

**Author:** ![cowboy\_x](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/d78d45/32.png) [@cowboy\_x](https://www.ruby-forum.com/u/cowboy_x)\
**Post date:** [February 20, 2008, 10:51pm UTC](https://www.ruby-forum.com/t/ruby-1-9-threads-and-freebsd-5/129662/8 "2008-02-20T22:51:24Z")

</div>

Mental G. wrote:

> Please note that you shouldn’t ever use the sleep trick in  
> production code – it merely hides problems during testing  
> when they can still occur under production load.

Oh yes, i know synchronization should never relies on temporisations…  
In this case, it’s useful to point the bug you mention in my use of  
#signal.

I’ve had wrote a general semaphore implementation using IO.pipe but your  
PortableSemaphore is way more elegant… thanks a lot (i just wonder if  
#up/#down honor the FIFO policy)

BTW, as for Queues : i admit i never use them.
