6

When I run the following code, I get some output:

use std::thread::Thread;

static DELAY: i64 = 1000;

fn main() {
    Thread::spawn(move || {
        println!("some output");
    });

    std::io::timer::sleep(std::time::duration::Duration::microseconds(DELAY));
}

But if I set DELAY to 999, I get nothing. I think that 999 and 1000 are close enough not to cause such a difference, meaning there must be something else going on here. I've tried also with Duration::nanoseconds (999_999 and 1_000_000), and I see the same behavior.

My platform is Linux and I can reproduce this behavior nearly all the time: using 999 results in some output in way less than 1% of runs.


As a sidenote, I am aware that this approach is wrong.

Community
  • 1
  • 1
tshepang
  • 12,111
  • 21
  • 91
  • 136
  • 4
    Can you reliable reproduce this, across different workloads and sessions? And what's your exact platform? I think the answer may well be hidden in your operating system's scheduler rather than any Rust code. –  Jan 06 '15 at 17:07
  • 1
    "I can reproduce this very reliably, but it doesn't happen 100% of the time." how reliable is that ? – exussum Jan 06 '15 at 17:13
  • @exussum: That must be 99% of the time ;-) – rodrigo Jan 06 '15 at 17:14
  • 1
    I am able to reproduce this on [play.rust-lang.org](http://is.gd/er2Xc1) (Try changing `+ 1` to `+ 0`). – Dogbert Jan 06 '15 at 17:14
  • That's why you shouldn't just guess when things are done, but check it (I've never done rust, so I don't know if the following piece of code is actually (thread-)safe, but it definitely works something along that way): [play.rust-lang.org](http://is.gd/KcHr3P). You may use a [condvar](http://doc.rust-lang.org/std/sync/struct.Condvar.html) for this to make it beautiful – stefan Jan 06 '15 at 17:23
  • 1
    I think this will boil down to things like "what version and options was your kernel compiled with" and "how many other programs are you running at the same time" and "what process scheduler are you using with what options". Said another way, there's probably some setting somewhere that schedules threads that happens to do one thing for >= 1ms and another for < 1ms. – Shepmaster Jan 06 '15 at 17:24
  • Can you reproduce it with this? https://gist.github.com/rninty/c15c45afe5e570e139cf – Ry- Jan 06 '15 at 17:33
  • @stefan Your playpen example goes into an infinite loop - `done` is not shared between the threads because of `move`. – wingedsubmariner Jan 06 '15 at 17:35
  • @wingedsubmariner As I said: never done anything with rust before. But this should be possible with a condvar as I also said. – stefan Jan 06 '15 at 17:36
  • @wingedsubmariner http://is.gd/UeaN62 I gather that's a valid approach, is it? – stefan Jan 06 '15 at 17:41
  • 1
    @stefan it's probably easier to use a [channel](http://doc.rust-lang.org/std/sync/mpsc/fn.channel.html), but that's starting to get into a new question that I'd encourage you to ask separately! – Shepmaster Jan 06 '15 at 17:44
  • @Shepmaster I'm not actually interested in this. I just wanted to point out that there are ways (no matter how they are called in this language and no matter which one is optimal) to actually do this properly ;-) – stefan Jan 06 '15 at 17:47
  • @stefan Your solution with the condvar looks perfectly valid to me. A channel may be simpler, but this works perfectly fine. – wingedsubmariner Jan 06 '15 at 17:48
  • @U2744SNOWFLAKE I can't, even when using 1 as an argument. Also, I sometimes get 2 `some output` lines with that code. – tshepang Jan 06 '15 at 18:00

2 Answers2

28

The sleep function sleeps in increments of 1 millisecond, and if the number of milliseconds is less than 1 it does not sleep at all. Here is the relevant excerpt from the code:

pub fn sleep(&mut self, duration: Duration) {
    // Short-circuit the timer backend for 0 duration
    let ms = in_ms_u64(duration);
    if ms == 0 { return }
    self.inner.sleep(ms);
}

In your code, 999 microseconds made it not sleep at all, and the main thread ended before the spawned thread could print its output. With 1000 microseconds, i.e. 1 millisecond, the main thread slept, giving the spawned thread a chance to run.

wingedsubmariner
  • 13,350
  • 1
  • 27
  • 52
-3

The most probable thing is you have your kernel configured to have a TICK of 1000Hz (once clock interrupt per millisecond) Perhaps you can improve it recompiling on a finer grained clock or a tickless kernel and recompiling your kernel to allow finer clock resolution. The 1000Hz clock tick is nowadays standard in Linux kernels running on pc (and most of ARMs and embedded Linux).

This is not a newbie issue, so perhaps you'll have to ask for local help to reconfigure and recompile your kernel to cope with more time resolution.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • that's not a reason to downvote... If it where, the thread might be closed and not allow more comments. I try to give some help, not to read all stackoverflow before answering. – Luis Colorado Jan 09 '15 at 05:31
  • The Answer I'm referring to was already Accepted on the Question you were Answering. – tshepang Jan 09 '15 at 16:15