2013-09-10 5 views
43

Каков наилучший способ сэкономить определенное время, но быть может прервано IsCancellationRequested от CancellationToken?Как «спать» до тех пор, пока не будет запрограммирован тайм-аут или аннулирование в .NET 4.0

Я ищу решение, которое работает в .NET 4.0.

Я хотел бы написать

void MyFunc (CancellationToken ct) 
{ 
    //... 
    // simulate some long lasting operation that should be cancelable 
    Thread.Sleep(TimeSpan.FromMilliseconds(10000), ct); 
} 

ответ

82

Я просто писал о нем здесь:

CancellationToken and Thread.Sleep

в Шорт:

var cancelled = token.WaitHandle.WaitOne(TimeSpan.FromSeconds(5)); 

В вашем контексте:

void MyFunc (CancellationToken ct) 
{ 
    //... 
    // simulate some long lasting operation that should be cancelable 
    var cancelled = ct.WaitHandle.WaitOne(TimeSpan.FromSeconds(10)); 
} 
+0

Я предпочитаю 'token.WaitHandle.WaitOne (TimeSpan.FromMilliseconds (5000)); 'но по сути это выглядит как самое чистое решение. – Onur

+3

Onur, тогда вы могли бы сделать это просто так: token.WaitHandle.WaitOne (5000) ' – Nekromancer

+0

Perfect Solution. Спасибо –

1

Лучшее решение, которое я нашел до сих пор является:

void MyFunc(CancellationToken ct) 
{ 
    //... 
    var timedOut = WaitHandle.WaitAny(new[] { ct.WaitHandle }, TimeSpan.FromMilliseconds(2000)) == WaitHandle.WaitTimeout; 
    var cancelled = ! timedOut; 
} 

UPDATE:

Лучшее решение до сих пор является accepted answer.

3

Чтобы отменить asynchronious операции по истечению определенного промежутка времени, пока еще в состоянии отменить операцию вручную использовать что-то вроде следующего

CancellationTokenSource cts = new CancellationTokenSource(); 
CancellationToken token = cts.Token; 
cts.CancelAfter(5000); 

это приведет к отмене через пять секунд. Чтобы отменить операцию, все, что вам нужно сделать, это передать token в ваш метод асинхронизации и использовать метод token.ThrowifCancellationRequested(), где вы настроили обработчик событий где-нибудь, чтобы запустить cts.Cancel().

Так полный пример:

CancellationTokenSource cts = new CancellationTokenSource(); 
CancellationToken token = cts.Token; 
cts.CancelAfter(5000); 

// Set up the event handler on some button. 
if (cancelSource != null) 
{ 
    cancelHandler = delegate 
    { 
     Cancel(cts); 
    }; 
    stopButton.Click -= cancelHandler; 
    stopButton.Click += cancelHandler; 
} 

// Now launch the method. 
SomeMethodAsync(token); 

Где stopButton кнопка нажатия кнопки, чтобы отменить выполняемую задачу

private void Cancel(CancellationTokenSource cts) 
{ 
    cts.Cancel(); 
} 

и метод определяется как

SomeMethodAsync(CancellationToken token) 
{ 
    Task t = Task.Factory.StartNew(() => 
     { 
      msTimeout = 5000; 
      Pump(token); 
     }, token, 
      TaskCreationOptions.None, 
      TaskScheduler.Default); 
} 

сейчас , чтобы вы могли работать с потоком, но также разрешаете аннулировать пользователя, вам нужно будет написать 'p umping»метод

int msTimeout; 
bool timeLimitReached = false; 
private void Pump(CancellationToken token) 
{ 
    DateTime now = DateTime.Now; 
    System.Timer t = new System.Timer(100); 
    t.Elapsed -= t_Elapsed; 
    t.Elapsed += t_Elapsed; 
    t.Start(); 
    while(!timeLimitReached) 
    { 
     Thread.Sleep(250); 
     token.ThrowIfCancellationRequested(); 
    } 
} 

void t_Elapsed(object sender, ElapsedEventArgs e) 
{ 
    TimeSpan elapsed = DateTime.Now - this.readyUpInitialised; 
    if (elapsed > msTimeout) 
    { 
     timeLimitReached = true; 
     t.Stop(); 
     t.Dispose(); 
    } 
} 

Примечание, SomeAsyncMethod возвратится прямо к абоненту. Чтобы заблокировать вызывающего абонента, вам придется переместить Task в иерархию вызовов.

+0

Благодарим за подробный ответ. Но я не думаю, что ваше представленное решение - это то, что я искал. Я хочу определить количество сна _ в функции, а не в том месте, где вызывается функция! Все дело в том, чтобы высмеять некоторую длительную операцию. И то, как журнал принимает это, не вызывает беспокойства вызывающий сайт. – Onur

+0

См. Редактирование. Кроме того, см. [Здесь] (http://stackoverflow.com/questions/9719003/spinwait-vs-sleep-waiting-which-one-to-use/9719357#9719357) для разницы между 'SpinWait' и' Sleep'. – MoonKnight

+0

Я вижу две проблемы с вашим решением: 1.) Он не блокирует выполнение, но сразу возвращается. Это что-то вроде «t.Wait()»; может решить. 2.) Его можно отменить только после того, как вы ожидаете количество времени, которое совершенно бессмысленно, так как я все равно уже закончен. – Onur

6

Кроме того, я думаю, что это довольно ясно:

Task.Delay(waitTimeInMs, cancellationToken).Wait(cancellationToken);

+1

Это не C# 4.0, а C# 4.5. – Onur

+1

Ответ от @Frode лучше. Причина? Слишком легко опустить «Wait()»; в конце нет ошибок компиляции, и это вообще не задерживает! Было сожжено это достаточно, что я просто предпочитаю вообще избегать этого синтаксиса. – Contango

+0

Я думаю, вам нужно обрабатывать исключения, как описано на https://msdn.microsoft.com/en-us/library/dd321315%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396 – granadaCoder

 Смежные вопросы

  • Нет связанных вопросов^_^