2013-02-25 21 views
68

Yukarıdaki kodla karşılaştırıldığında for class RulyCanceler, kodu CancellationTokenSource kullanarak çalıştırmak istedim.CancellationToken özelliği nasıl kullanılır?

Cancellation Tokens numaralı belgede belirtildiği gibi, yani bir istisna atmadan/yakalamadan nasıl kullanabilirim? IsCancellationRequested özelliğini kullanabilir miyim?

böyle kullanmaya teşebbüs:

cancelToken.ThrowIfCancellationRequested(); 

ve

try 
{ 
    new Thread(() => Work(cancelSource.Token)).Start(); 
} 
catch (OperationCanceledException) 
{ 
    Console.WriteLine("Canceled!"); 
} 

ancak bu yöntemin Work(CancellationToken cancelToken) yılında cancelToken.ThrowIfCancellationRequested(); bir çalışma zamanı hata verdi:

System.OperationCanceledException was unhandled 
    Message=The operation was canceled. 
    Source=mscorlib 
    StackTrace: 
     at System.Threading.CancellationToken.ThrowIfCancellationRequested() 
     at _7CancellationTokens.Token.Work(CancellationToken cancelToken) in C:\xxx\Token.cs:line 33 
     at _7CancellationTokens.Token.<>c__DisplayClass1.<Main>b__0() in C:\xxx\Token.cs:line 22 
     at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ThreadHelper.ThreadStart() 
    InnerException: 

kodu başarıyla koştum OperationCanceledException th içinde yakalandı E yeni iplik şu şekildedir:

using System; 
using System.Threading; 
namespace _7CancellationTokens 
{ 
    internal class Token 
    { 
    private static void Main() 
    { 
     var cancelSource = new CancellationTokenSource(); 
     new Thread(() => 
     { 
     try 
     { 
      Work(cancelSource.Token); //).Start(); 
     } 
     catch (OperationCanceledException) 
     { 
      Console.WriteLine("Canceled!"); 
     } 
     }).Start(); 

     Thread.Sleep(1000); 
     cancelSource.Cancel(); // Safely cancel worker. 
     Console.ReadLine(); 
    } 
    private static void Work(CancellationToken cancelToken) 
    { 
     while (true) 
     { 
     Console.Write("345"); 
     cancelToken.ThrowIfCancellationRequested(); 
     } 
    } 
    } 
} 

cevap

82

Sen iş yöntemi uygulayabilirsiniz: bu kadar

private static void Work(CancellationToken cancelToken) 
{ 
    while (true) 
    { 
     if(cancelToken.IsCancellationRequested) 
     { 
      return; 
     } 
     Console.Write("345"); 
    } 
} 

. Her zaman kendiniz iptal işlemek gerekir - bu (iş ve verilerin tutarlı bir durumda olacak şekilde) çıkmak için uygun zaman yönteminden çıkış

GÜNCELLEME: genellikle birkaç çıkış vardır çünkü while (!cancelToken.IsCancellationRequested) yazmıyoruz tercih döngü gövdesinde güvenli bir şekilde çalışmayı durdurabileceğiniz noktalar ve döngü genellikle çıkış için bazı mantıksal koşullara sahiptir (koleksiyondaki tüm öğeler üzerinde yineleme vb.). Dolayısıyla, bu koşulları farklı niyetleri olduğu gibi karıştırmamanın daha iyi olduğuna inanıyorum.

+1

teşekkürler! Bu online metin, oldukça yetkili ("Nutshell" C# 4.0 "kitap?) Takip etmiyor. Bana "her zaman" hakkında bir referans verebilir misin? – Fulproof

+1

Bu, pratikten ve deneyimden gelir =). Bunu nereden bildiğimi hatırlayamıyorum. "Her zaman ihtiyacın var" demiştim, çünkü Thread.Abort() 'ı kullanarak dışarıdan bir istisna dışında iş parçacığı parçasını kesebilirsin, ama bu çok kötü bir uygulama. Bu arada, CancellationToken.ThrowIfCancellationRequested() kullanarak da "bunu kendi başına iptal et", sadece bunu yapmak için başka bir yoldur. –

+0

^bu doğru. Bunun yerine "if" bloğu yerine "cancelToken.ThrowIfCancellationRequested();" Bazen belgeler/kitaplar kapalı (MVP'ler tarafından yazıldığı zaman bile) - bu talihsiz bir durumdur, ancak belki bir sonraki baskıda düzeltilecektir. Bu arada, belki de kitabın çevrimiçi bir errata sitesi olup olmadığını kontrol edebilirsiniz (ve eğer bir hata belirtilmemişse, belki de bulgularınızı gelecekteki düzeltmeler için yazara gönderebilirsiniz). – BrainSlugs83

46

Böyle kullanabilirsiniz:

var cancelToken = new CancellationTokenSource(); 
    Task.Factory.StartNew(() => DoExternalWork(), cancelToken.Token); 

    Thread.Sleep(1000); //simulate some other work 

    //this stops the Task: 
    cancelToken.Cancel(false); 
+0

Bunu işe yaramadı - doğru ya da yanlış geçip geçmediğimde, görev çalışmaya devam ediyor. Neyi kaçırıyorum? – BrainSlugs83

+1

Oh, lame - uzun süre çalışan metodunuzda CancellationToken'e erişiminiz olmalı ve "token.ThrowIfCancellationRequested();" atılan istisnayı istediğiniz noktada - bunun anlamı nedir? Sadece şunu söyleyebilirsiniz: (belirteci.IsCancellationRequested) {yeni MyExceptionBecauseBlah() at; } '- Ayrıca, hala doğru veya yanlış arasında bir fark görmüyor - istisna her iki şekilde atılır. – BrainSlugs83

+3

@ BrainSlugs83 Bu basit, CancellationToken, görevlerin evrensel bir şekilde kasıtlı olarak iptal edilmesine izin veren bir iletişim standardıdır. Bu nedenle, niyetini, daha önce olduğu gibi milyonlarca farklı yoldan geçmek zorunda kalmak yerine (yani, "e.Cancel = true" veya "bool _aborted gibi şeyler kullanarak; (! Iptal edildi) ...", artık bir basit bir ortak şema - yönteminizin iptalini destekliyor mu? Bir CancellationToken parametresi almasına izin verin ve iptal talebinde bulunup bulunmadığını sormak için bunu kullanın. "Thread.Abort" veya " Process.Kill ' – Luaan

20

BrainSlugs83

@ Sen körlemesine stackoverflow yayınlanan her şeyi güven olmamalıdır. Jens kodundaki yorum yanlıştır, parametre istisnaların atılıp atılmadığını kontrol etmez.

MSDN, bu parametre denetimlerinin neyi okuduğunu açıkça biliyor mu? throwOnFirstException doğruysa http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx

bir istisna hemen işlenmekte olan kalan geri aramalar ve iptal işlemleri önler İptal çağrısına dışına yayılır. throwOnFirstException yanlışsa, bu aşırı yükleme, bir AggregateException içine atılan tüm istisnalarını toplar, böylece bir istisna atayan bir geri çağrısı, tarafından yürütülen diğer kayıtlı geri aramaların yürütülmesini engelleyemez. kendisi belirteci değil CancellationTokenSource üzerinde denir İptal çünkü

değişken adı

da yanlıştır ve kaynak her yönettiği belirteç durumunu değiştirir.

+0

Ayrıca, iptal belirtiminin önerilen kullanımıyla ilgili belgelere (TAP) bakınız: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based- asenkron-desen-musluk # iptal-opsiyonel – Epstone

5

İstisnai kullanmadan ThrowIfCancellationRequested'i kullanabilirsiniz!

ThrowIfCancellationRequested kullanımı, Görev (bir Thread değil) içinden kullanılmalıdır. Bir Görev içinde kullanıldığında, kendiniz istisna işlemek zorunda kalmazsınız (ve İşlenmeyen Özel Durum hatası alırsınız). Görev bırakarak sonuçlanır ve Task.IsCancelled özelliği True olacaktır. İstisna işlemine gerek yok.

Özel durumda, iş parçacığı bir görev için değiştirin. Kullanıcılara uygulamanın git arkaplan Bu simgeyi iptal edebilirsiniz

try 
{ 
    var t = new Task(() => Work(cancelSource.Token)); 
    t.Start(); 
} 
if (t.IsCancelled) 
    Console.WriteLine("Canceled!"); 
} 
+0

Neden 't.Start()' ve 'Task.Run()' kullanıyorsunuz? –

+0

@XanderLuciano: Bu örnekte belirli bir neden yok ve Task.Run() daha iyi bir seçim olurdu. – Titus

2

Sen iptal jetonu Görev oluşturabilir.

Sen, Anter çözüm Xamarin.Forms kullanıcı Timer olan PCL https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle

var cancelToken = new CancellationTokenSource(); 
Task.Factory.StartNew(async() => { 
    await Task.Delay(10000); 
    // call web API 
}, cancelToken.Token); 

//this stops the Task: 
cancelToken.Cancel(false); 

bunu sayacı durdurabilirsiniz zaman uygulaması git arka plan https://xamarinhelp.com/xamarin-forms-timer/

İlgili konular