codegram / futuroscope

Yet another Futures implementation in Ruby
MIT License
209 stars 13 forks source link

Fixed race condition with 2 threads waiting on the same future #14

Closed ggPeti closed 10 years ago

ggPeti commented 10 years ago

When 2 threads try to access the same future that has not been resolved yet, both threads start to pop the future's internal queue. But since only one value will ever get pushed to that queue, one of the threads will hang forever.

The solution is to use a mutex, preferably with double checked locking on resolved_future_value. This way only one thread will ever block the Future's internal queue, the rest blocks on the mutex and will correctly obtain the value afterwards.

This behavior might have sparked the following line in the original blog post:

You could reach dead locks when you're calling futures inside of futures (because of the thread pool). You shouldn't be doing that.

Currently I see no other way of reaching a deadlock, so this might be obsolete information after the fix, but I haven't proven this.

josepjaume commented 10 years ago

Thanks again!

Futuroscope's thread pool is used in order to ensure you don't end up with a gazillion of threads when dealing with a lot of concurrency.

If you use futures that have to wait for other futures to be resolved, you might end up in a situation where you filled up the thread pool, and those nested futures can't resolve because they don't get processed by the pool. Any ideas on how to fix that behavior? It should be easily reproducible in a spec.

That said, this is an awesome fix. For some reason I never thought about calling the same future from different threads.

Thanks again!

ggPeti commented 10 years ago

Oh yeah, that's definitely true, missed that. A simple case is future { future { 1 } + 1 } with a pool size of 1. I'll investigate if there's a simple solution for that!