Есть ли способ разбудить спящую нить? - PullRequest
13 голосов
/ 11 августа 2010

Есть ли способ разбудить спящий поток в C #? Итак, не спите ли вы долго и не будите ли вы, когда хотите обработать работу?

Ответы [ 7 ]

16 голосов
/ 11 августа 2010

Объект AutoResetEvent (или другая реализация WaitHandle) может использоваться для перехода в спящий режим до получения сигнала от другого потока:

// 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();
5 голосов
/ 11 августа 2010

Если ваш поток находится внутри вызова Sleep, то (как правило) нет способа его разбудить. (Единственное исключение, о котором я знаю, это Java, который позволяет завершать сон раньше, если какой-то другой поток вызывает thread.interrupt().)

Кажется, что шаблон, о котором вы говорите, вызывает событие: поток содержит цикл, в верхней части которого он ожидает запуска события. Если событие в данный момент не установлено, то поток «спит», пока какой-то другой поток не запустит событие. В этот момент спящий поток просыпается и продолжает свою работу, пока в следующий раз не пройдет цикл, ожидая другого события.

2 голосов
/ 17 апреля 2018

На самом деле существует метод thread.Interrupt () в C #.В то время как принятый ответ действительно описывает хороший шаблон, который вы, вероятно, хотите получить в вашем случае, я пришел к этому вопросу в поисках Thread.Interrupt, поэтому я помещаю его здесь.

1 голос
/ 11 августа 2010

Лучшим решением будет использование Task объектов со значением по умолчанию TaskFactory.Этот API (представленный в .NET 4.0) использует пул потоков с очередями для кражи работы и все эти причудливые вещи.

Если .NET 4.0 недоступен, тогда используйте ThreadPool, который имеетвстроенная рабочая очередь (которая выполняет некоторую балансировку пула, но не в той же области, что и пул потоков 4.0).

Если вы действительно должны сделать это самостоятельно, тогда я рекомендую BlockingCollection<T>, которая является блокирующей очередью потребителя / производителя, добавленной в .NET 4.0.

Если вы действительно должны сделать это самостоятельно и не можете использовать .NET 4.0,тогда вы можете использовать ManualResetEvent или AutoResetEvent вместе с lock -защищенной очередью работы.

0 голосов
/ 31 мая 2018

Расширяя ответ Вима, вы также можете указать время ожидания для звонка WaitHandle.WaitOne(). Таким образом, вы можете использовать вместо Thread.Sleep(). CancellationToken struct предоставляет вам один, чтобы вы могли сигнализировать о ваших задачах следующим образом:

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
}
0 голосов
/ 20 мая 2018

По предложению Ильи:

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

и ...

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

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

Это грубое решение, поскольку могут быть другие причины, по которым выбрасывается ThreadInterruptedException.

0 голосов
/ 11 августа 2010

Может ли эта тема помочь?C # имеет хорошую функциональность для обработки событий потока.Я выполнил большую часть своей работы на Python, но, похоже, в C # есть надежные библиотеки для блокировки потоков.

...