igrigorik/agent — Issue #8: More race conditions in the selector
Author: nate
Created: 2012-03-03 03:25:13+00:00
State: open

If you check out go's [select statement](http://weekly.golang.org/doc/go_spec.html#Select_statements), you'll notice that receiving and sending actual values are part of the case conditions. I think this is so they can make it atomically receive from or send to one and only one channel.

Agent's API looks like this, presently:

```ruby
old_value = 3

select do |s|
s.case(cr, :receive) { |c| new_value = c.receive }
s.case(cw, :send) { |c| c.send old_value }
end
```

If the `cr` channel becomes available for receive first, it will have its block called. A race condition is introduced, however, because the thread could switch context away from the block at any time and another thread could call receive on the channel and steal its value. If this happens and we switch back to the block, we could get stuck at the `c.receive` call indefinitely.

The only way to prevent this from occurring with the current syntax is to put a lock on the channel for the entire block's duration so that its state is preserved (the state of being able to send to or receive from the channel). That's not desirable at all, especially since this could become circular and you could end up with deadlocks.

It's becoming much clearer why go implemented the select this way.

I propose a new syntax that is more similar to go's and is easier to prevent race conditions with:

```ruby
old_value = 3

select do |s|
s.case(cr, :receive) { |new_value| puts "The new value is that was received is #{new_value}" }
s.case(cw, :send, old_value) { puts "Old value was sent via the channel at this point" }
end
```

I think this is much closer to the way that go functions, will prevent undesirable behavior as I described above, and gives us the best chance of making this library truly thread safe.