Closed klobuczek closed 1 year ago
IIRC, this is because let
blocks are "thread safe" and have an implicit shared mutex around every request. It's supposed to be reentrant but because Sync { param }
happens on a different fiber, it's effectively a deadlock, i.e. it's not that different from:
m = Thread::Monitor.new # recursive mutex
param = lambda{m.synchronize{1}}
s = lambda{m.synchronise{Thread.new{param.call}.value}}
s.call
To resolve s
it locks the mutex for the current (main) thread. Then it creates a new thread (Sync
block creates a new fiber) and then tries to lock the mutex again and this deadlocks.
The real issue here is whether RSpec should be "thread safe" in this way. I personally think it's wrong.
I got pretty frustrated with RSpec for this reason as well as others, and implemented https://github.com/ioquatix/sus which explicitly avoids this problem. I don't have a good answer and can't fix RSpec, maybe they will avoid having a mutex around their let variables.
I cannot figure out why the spec in the 2nd context does not terminate:
Using ruby 3.1.2 and async 2.0.2.