| My opinion is tokio’s Mutex [0] is too fair. It passes ownership directly to the next future in the lock queue. If it was instead more similar to a futex [1], this problem could have been avoided. My assumption is that tokio went with this design because simple Future subexecutors [2] tend to have very poor scheduling. Often they poll each of their child futures in turn regardless of which were actually woken. With an async locks closer in design to a futex, this could lead to subexecutor child futures being starved out. If that was truly tokio’s reasoning for the design of their Mutex, I still kinda disagree with the choice; it shouldn’t be the lock’s job to fix tokio::select! being bad at scheduling. [0]: We should be specific that we’re discussing tokio’s Mutex. this is one particular implementation of async locks. [1]: wake next in queue, but don’t pass ownership. the woken task must CAS to actually acquire. [2]: think tokio::select! or futures_lite::future::Or. but not FuturesUnordered which does child wakeups properly. |
...sometimes? Wouldn't we still have the problem if the future runs (actually getting the lock) but then awaits again while holding it? I think that's common—if you're not awaiting while holding the lock, then why didn't you just use a simple std::sync::Mutex?