Question

Before people suggest it: I am not using Thread.sleep for anything except trying to find a way to work around it. I am trying to handle other people's future code which may not be .Sleep() free. I have a very good grasp of how horrible it is for synchronizing things.

I accept a thread in a chunk of my code. I wish to be able to set a limit to this thread's lifetime. My usual method of doing so goes like this:

Thread outer = new Thread(() =>
{
    externalThread.Start();
    externalThread.Join();
});
outer.Start();
outer.Join(lifetime);
if (outer.ThreadState != ThreadState.Stopped)
{
    outer.Abort();
}
inner.Join();

I've since discovered that I apparently cannot wake a sleeping thread before the sleep finishes. To make matters worse, this still writes to the console if I give it a lifetime of 10 milliseconds:

new Thread(() => { Thread.Sleep(2000); Console.WriteLine("second"); })

Though I realize .Abort() isn't a hard-limit on thread execution. It seems 2 seconds would be enough of a warning, but I guess not...

I've tried checking for WaitSleepJoin status, and .Interrupt(); it crashes the thread, or throws an exception (sorry, unsure which. Windows tells me it crashed if no debugger's running, and if it is running it runs as if interrupt wasn't called), and still writes to the console after 2 seconds. .Resume() apparently does nothing to a sleeping thread.

Is there a way to wake a thread, without waiting for its Sleep to expire? I understand that stopping isn't "immediate", so that Console.WriteLine may be called regardless; it's the 2 second wait that's bugging me. What if it's a 10 day wait? Since I can't control the threads that come in, I have no way of knowing, and it seems no way of preventing such a thing...

Was it helpful?

Solution

No there is no way wake a thread from a sleep. You can only Abort a thread by calling Abort or Interrupt (both of which throw a ThreadAbortException).

But to address you question of why when running:

new Thread(() => { Thread.Sleep(2000); Console.WriteLine("second"); })

with a 10ms timeout still prints, it is because your code for controlling the thread life time doesn't do what you want to do.

So you've got externalThread and outer. You start outer (which starts a new thread, lets call it thread 1) and from outer call start on external thread (which starts a new thread, lets call it thread 2). So you have just started two new threads.

When you call outer.About(), that aborts only thread 1. The thread started by calling externalThread.Start(), thread 2 continues executing to completion since nothing aborts it.

I'm not sure what your are trying to accomplish with the extra outer thread. Wouldn't this be simpler:

externalThread.Start();
externalThread.Join(lifetime);
if (externalThread.ThreadState != ThreadState.Stopped)
{
    externalThread.Abort();
}

OTHER TIPS

Use WaitOne + timer to control threads of unknown origin.

or if you'd have control over the thread's worker code:

kinda hacky way, to achieve more "responsive sleep" when not liking timers/other threads used to wake the thread up

use it in place of normal Thread.Sleep

    private void WaitFor(int milis)
    {
        const int interval = 500;

        if (milis <= interval)
        {
            throw new ArgumentException();
        }

        var sections = milis / interval;
        for (var s = 0; s < sections && (!ShouldQuit); ++s)
        {
            Thread.Sleep(interval);
        }
    }

notice the ShouldQuit flag, being a class field accessible from both threads

of course this has worse cpu-usage characteristics than event/timer based wait

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top