crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.35k stars 1.62k forks source link

Buffered Channel with overflow capacity doesn't raise #1866

Closed askn closed 8 years ago

askn commented 8 years ago

I wanted to test out Buffered Channels but seems like the capacity option is not being used. This code compiles but it just locks the process without any output.

ch = Channel::Buffered(Int32).new(2)
ch.send 7
ch.send 5
ch.send 6
ch.send 2

loop {
  puts "Yo"
  ch.receive
}
asterite commented 8 years ago

Yes, that's the expected behaviour. Once you try to send the third number it blocks the current coroutine, which is the main and only one, because the capacity is 2.

What you probably want is this:

ch = Channel::Buffered(Int32).new(2)

# Send messages in a different coroutine: if `send` blocks, it will block just this couroutine
spawn do
  ch.send 7
  ch.send 5
  ch.send 6
  ch.send 2
end

# This is on the main coroutine. `receive` blocks until it gets messages from `send`, 
# and now it works because two coroutines are communicating
loop {
  puts "Yo"
  ch.receive
}
askn commented 8 years ago

I thought that it should raise an exception if the capacity is full or over like in Go e.g http://play.golang.org/p/94yoBGi0Zz

asterite commented 8 years ago

In Go it panics because the runtime detects that there's a deadlock. We can do the same, but right now it's not done. In a way, both programs crash: Go with panic, Crystal hangs forever.

jhass commented 8 years ago

The exception seems to be because of a deadlock, not because the channel is full. We might do deadlock detection in the future, but that's a separate topic.

Edit: Ah, too slow.

jhass commented 8 years ago

Closing, please open a separate issue if you want deadlock detection.