-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API convention for blocking-, timeout-, and/or deadline-related functions #46316
Comments
@alexcrichton, as requested in #45969, I'm cc-ing you here to discuss which API we want for deadline-related functions. |
parking-lot uses |
Thanks @sfackler for the parking-lot example. This example actually conflicts with the standard library versions and extends the "no meaningful blocking version" suggestion above to functions that actually have a blocking version. If I reformulate the suggestion according to this information, it would be:
These rules overlap which is unfortunate, but this is maybe the freedom we need to account for the current state of naming by interpreting the primary role of a function differently. For example, for the standard library, the main role of Just to clarify, with the current suggestion (and the first one which was very similar), Here is the current suggestion (and whether it differs from the current state):
|
I took the time to go over the existing crates by downloading the latest version of each crate and grepping for public functions taking an
I changed the terminology for timeout and deadline versions to duration and instant versions to reflect the types and avoid possible biaises. Here are some examples according to the 4 versions (blocking, non-blocking, duration, and instant):
Using
We see some usage of
Some outsiders:
|
It's worth pointing out that there may also just not be a convention to be had here. There's certainly not an "obvious agreement" amongst everything today it seems like and I wouldn't want to bend over too much to try to fit things in! That being said I do sort of like the |
This thread suggests renaming This issue is now also the tracking issue for |
I created this issue in response to #45969 (comment). Maybe we should split it between the tracking issue of What is the timeline for a tracking issue? Should we keep it open until the feature goes stable? Is there any time constraints about this? |
There is no time constraint. A tracking issue stays open until the corresponding feature becomes stable (in the sense of: does not require |
Now that |
I've mentioned this in a couple of places but, since this seems to be the issue that has the most focus on Pulling my example from this issue: pub fn sleep_until(deadline: Instant) {
let now = Instant::now();
// What if the thread is suspended here? If that happens, you are no longer sleeping until `deadline` but
// are instead sleeping until `deadline + epsilon` which is not universally acceptable.
if let Some(delay) = deadline.checked_duration_since(now) {
thread::sleep(delay);
}
} Some of the functions described in this issue are likely too high-level to be used by applications which care about this level of accuracy (e.g., I would be surprised if such an application used the |
How is that functionally different from the OS not scheduling your thread for some period of time after the timer triggers, or the thread getting suspended immediately after being woken up? Or for that matter if the thread is suspended immediately before the call to On a per-emptively scheduled OS, I don't think there is any way to guarantee your thread is awoken precisely at a given time. |
I think a better question is: why not just do it correctly? What is the appeal of writing an incorrect version when the OSes make it so easy to do it correctly? But, to use a more complex (but more accurate) example: On Unix, sleeping for a duration is implemented via nanosleep in a loop, where the remaining time is returned by the call and used as the remaining time if the sleep is interrupted. Quoting the Linux Programming Interface on this exact situation (emphasis mine):
Note that So, right there on the surface, we have one type of program where implementing In my specific use case, I'm running robotic control on a fairly underpowered SBC. I am not so low level as to be embedded (i.e., I do have an OS) but I have done everything in my power to make sure that the thread is going to wake up at exactly the specified time (e.g., I have completely removed one of the cores from scheduling and have dedicated it to my control loop, among other things). This control loop is vaguely similar to the following: fn run() {
let deadline = Instant::now() + INTERVAL;
loop {
do_quick_calculation_and_set_pins();
thread::sleep_until(deadline);
deadline += INTERVAL;
}
} Looking at that code, I am explicitly avoiding calls to tl;dr: It's so trivially easy to do this correctly, why go out of your way to make Rust unsuitable for niche (but valid) programs? |
I'm not saying it shouldn't be done correctly. My point is that it doesn't completely solve the problem of your thread getting interrupted at an inopportune time. |
Of course. That wasn't meant to be a definitive guide on how to wake up as accurately as possible, just an easy to grok example. |
The standard library currently exposes several blocking- and/or timeout-related functions:
std::sync::Condvar::wait*
wait
wait_timeout_ms
wait_timeout
std::sync::mpsc::Receiver::recv*
recv
recv_timeout
std::thread::park*
park
park_timeout_ms
park_timeout
std::thread::sleep*
sleep_ms
sleep
The timeout versions taking a
u32
in milliseconds are actually deprecated for the version taking aDuration
since1.6.0
.This issue tracks the possibility to extend these APIs and provide a convention for blocking-, timeout-, and/or deadline-related functions. The current suggestion is:
std::sync::Condvar::wait*
wait
wait_timeout
wait_deadline
std::sync::mpsc::Receiver::recv*
recv
recv_timeout
recv_deadline
std::thread::park*
park
park_timeout
park_deadline
std::thread::sleep*
sleep_for
sleep_until
The blocking versions do not take any extra argument and are not suffixed. The timeout versions take a timeout as a
Duration
and return if this timeout is reached (the timeout starts when the function is called with best-effort precision). They are suffixed by_timeout
. The deadline versions take a deadline as anInstant
and return if this deadline is reached (the deadline precision is best-effort). They are suffixed by_deadline
.For functions that do not have a meaningful blocking version (like sleep which would essentially block until the program ends), the timeout version would be suffixed by
_for
and the deadline version would be suffixed by_until
. We don't have enough data-points to see if this rule is actually applicable. In a first iteration, we could leave aside those functions that do not have a meaningful blocking version.The text was updated successfully, but these errors were encountered: