Is there a way to wake a sleeping thread?

試著忘記壹切 提交于 2019-11-30 17:36:34

An AutoResetEvent object (or another WaitHandle implementation) can be used to sleep until a signal from another thread is received:

// launch a calculation thread
var waitHandle = new AutoResetEvent(false);
int result;
var calculationThread = new Thread(
    delegate
    {
        // this code will run on the calculation thread
        result = FactorSomeLargeNumber();
        waitHandle.Set();
    });
calculationThread.Start();

// now that the other thread is launched, we can do something else.
DoOtherStuff();

// we've run out of other stuff to do, so sleep until calculation thread finishes
waitHandle.WaitOne();

If your thread is inside a call to Sleep, then there isn't (usually) a way to wake it up. (The only exception I'm aware of is Java, which allows a sleep to be ended early if some other thread calls thread.interrupt().)

The pattern that you're talking about seems to call for an event: the thread contains a loop, at the top of which it waits for an event to fire. If the event is currently unset, then the thread "sleeps" until some other thread fires the event. At that point, the sleeping thread wakes up and continues its work, until the next time through the loop when it sleeps to wait for another event.

There is actually a thread.Interrupt() method in C#. While the accepted answer does describes a good pattern that you probably want in your case, I came to this question looking for Thread.Interrupt so I am putting it here.

The best solution would be to use Task objects with the default TaskFactory. This API (introduced in .NET 4.0) uses a pool of threads with work-stealing queues and all that fancy stuff.

If .NET 4.0 isn't available, then use the ThreadPool, which has a built-in work queue (which does some pool balancing but not on the same scope as the 4.0 thread pool).

If you really must do it yourself, then I recommend a BlockingCollection<T>, which is a blocking consumer/producer queue added in .NET 4.0.

If you really must do it yourself and can't use .NET 4.0, then you can use a ManualResetEvent or AutoResetEvent along with a lock-protected queue of work.

krs1

Would this thread help? C# has good functionality for thread Event handling. I've done most of my work in Python, but C# seems to have solid libraries for thread blocking.

Based on Ilia's suggestion:

t1 = new Thread(() =>
    {
     while (keepRunning) {
         try {
             DoWork();
             Thread.Sleep(all_night_long);
             }
         catch (ThreadInterruptedException) { }
         }
    });
t1.Start();

and...

public void WakeUp()
{
   t1.Interrupt();
}

public void StopRunningImmediately()
{
   keepRunning = false;
   WakeUp(); //immediately
}

This solution is crude, as there may be other reasons why the ThreadInterruptedException is thrown.

Expanding Wim's answer you can also specify a timeout for the WaitHandle.WaitOne() call. So you can use instead of Thread.Sleep(). CancellationToken struct provides you with one so you can signal your tasks like this:

string SleepAndWakeUp(string value,CancellationToken ct)
{
    ct.WaitHandle.WaitOne(60000);
    return value;
}

void Parent()
{
     CancellationTokenSource cts = new CancellationTokenSource();
     Task.Run(() => SleepAndWakeUp("Hello World!", cts.Token), cts.Token);
     //Do some other work here
     cts.Cancel(); //Wake up the asynch task
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!