This causes a deadlock with 1.4.0 :
async fn f() {
{
let _ = async_std::io::stdout().lock().await;
}
{
let _ = async_std::io::stdout().lock().await;
}
}
I'm noticing something similar with some mutexes at the moment. I'll see if I can post some sample code tomorrow to reproduce my issue. It looks like mutexes don't relinquish locks, even when I make the calls to drop() explicitly.
async_std::io::StdoutLock is a thin wrapper around similar struct from std
with an additional unasfe impl of Send trait. The mutex used internally in
std::io::StdoutLock can be unlocked only from the same thread.
Thus in scenario above unlocking will fail (silently or with panic, depending
on debug assertions in std), hence a deadlock.
@tmiasko Does anything similar apply to Mutex, or does this just affect StdoutLock?
The mutex used internally in std::io::StdoutLock can be unlocked only from the same thread.
@tmiasko could you perhaps share more on this?
Typically a mutex can be unlocked only by the owner, i.e., thread that locked it. The std::io::StdoutLock is no different since on POSIX systems it uses pthread mutex with such a requirement. It is also marked as !Send to enforce that.
Interesting. This could be pretty confusing and counter-intuitive behavior for many people. Are there any plans to address this sort of behavior within async-std? I'm assuming fixing this would require changes to the task scheduler, at the very least.
@Noah-Kennedy from talking with @stjepang in a call yesterday, we're considering maybe dropping this range of APIs all together. The new scheduler outlined in https://github.com/async-rs/async-std/pull/631 would help with any (potentially) slow IO.
There are probably ways of writing true async stdio APIs, but to make them coordinate with std seemingly requires a lot of effort, and probably buy-in from std itself too. #631 might just be the best option we have for the foreseeable future.
@yoshuawuyts which APIs would be dropped? stdout() and Mutex?
I could see the new scheduler allowing those to be removed, with people just using the Mutex and blocking IO in std, especially where said IO involves a lock.
@Noah-Kennedy just stdout/stdin/stderr; our async mutex impl actually has distinct benefits compared to always blocking threads.
Most helpful comment
Typically a mutex can be unlocked only by the owner, i.e., thread that locked it. The
std::io::StdoutLockis no different since on POSIX systems it uses pthread mutex with such a requirement. It is also marked as!Sendto enforce that.