`Thread::park_waker`: a `Waker` calling `Thread::unpark`

Currently, it's quite tedious to share code between synchronous and asynchronous implementations. For example, you have to use std::task::Waker in low-level asynchronous implementation, while you may opt for std::thread::park in synchronous one.

However, std::thread::Thread::unpark is quite similar to std::task::Waker, in fact, one can easily make a unpark waker from std::thread::Thread. But it requires to wrap the Thread in an Arc, while the internal implementation of Thread is already an Arc, so it's quite suboptimal.

That's why I suggest adding a method std::thread::Thread::park_waker(self) -> std::task::Waker.

It would for example allow using data structures like futures::task::AtomicWaker with thread parking, and factoring both synchronous and asynchronous implementation. You may argue that data structures like AtomicWaker should be made generic instead, and that's a good point, but I'm still in favor of standardization through the Waker type.

It could also be implemented in a separate crate (I will maybe do this if my proposition is rejected), but I really think it should be in the standard library, as it's a std waker implementation for a std type. (impl From<std::thread::Thread> for std::task::Waker could also be added)

2 Likes

Depending on the exact use case "quite easily" may not be so easy, futures::block_on had a lost-wakeup issue with a naive wake -> unpark mapping:

Thank you for this interesting issue. In fact, I was not thinking about an executor use case, which must handle arbitrary user code; a warning should be written in park_waker documentation about interference with unexpectedunpark calls.

My use case, however, is completely different: a concurrent datastructure with blocking/asynchronosous operation; there cannot be any intereference because there is no unepected unpark. It allows avoiding things like

enum Waker {
    Sync(Thread),
    Async(task::Waker),
}
impl Waker {
    fn wake(self) {
        match self {
            Self::Sync(thread) => thread.unpark()
            Self::Sync(waker) => waker.wake()
        }
    }
}

and using AtomicWaker instead of reimplementing it. I should have better explained my use case at first, indeed.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.