रद्दीकरण संपत्ति का उपयोग कैसे करें?


117

वर्ग RulyCanceler के लिए पूर्ववर्ती कोड की तुलना में , मैं कोड का उपयोग करके चलाना चाहता था CancellationTokenSource

मैं इसे अपवाद के रूप में रद्द करने , / बिना किसी अपवाद को पकड़ने के रूप में कैसे उपयोग करूँ ? क्या मैं IsCancellationRequestedसंपत्ति का उपयोग कर सकता हूं ?

मैंने इसे इस तरह उपयोग करने का प्रयास किया:

cancelToken.ThrowIfCancellationRequested();

तथा

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

लेकिन इसने cancelToken.ThrowIfCancellationRequested();विधि में एक रन-टाइम त्रुटि दी Work(CancellationToken cancelToken):

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:

कोड जो मैंने सफलतापूर्वक चलाया, ने नए धागे में OperationCanceledException को पकड़ा:

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();
      }
    }
  }
}

2
docs.microsoft.com/en-us/dotnet/standard/threading/… में CancellationTokenSourceasync विधियों के साथ उपयोग करने, मतदान के साथ लंबे समय तक चलने के तरीकों और कॉलबैक का उपयोग करने के कुछ बहुत अच्छे उदाहरण हैं ।
एहतेश चौधरी

यह लेख आपके पास मौजूद विकल्पों को दिखाता है और आपको अपने विशिष्ट मामले के अनुसार टोकन को संभालने की आवश्यकता है।
ओग्यान दिमित्रोव

जवाबों:


140

आप अपनी कार्य विधि इस प्रकार से कार्यान्वित कर सकते हैं:

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

बस। आपको हमेशा स्वयं को रद्द करने की आवश्यकता होती है - विधि से बाहर निकलें जब बाहर निकलने का उचित समय हो (ताकि आपका काम और डेटा सुसंगत हो)

अद्यतन: मैं लिखना पसंद नहीं करता while (!cancelToken.IsCancellationRequested)क्योंकि अक्सर कुछ निकास बिंदु होते हैं जहां आप लूप बॉडी पर सुरक्षित रूप से निष्पादित करना बंद कर सकते हैं, और लूप में आमतौर पर बाहर निकलने के लिए कुछ तार्किक स्थिति होती है (संग्रह आदि में सभी वस्तुओं पर पुनरावृति)। इसलिए मेरा मानना ​​है कि बेहतर नहीं है कि वे शर्तों को मिलाएं क्योंकि उनका अलग इरादा है।

परहेज के बारे में सावधानी नोट CancellationToken.ThrowIfCancellationRequested():

Eamon Nerbonne द्वारा प्रश्न में टिप्पणी :

... इस जवाब के अनुसार, इनायत के ThrowIfCancellationRequestedलिए चेक के एक गुच्छा के साथ प्रतिस्थापित करना IsCancellationRequested। लेकिन यह केवल एक कार्यान्वयन विवरण नहीं है; यह देखने योग्य व्यवहार को प्रभावित करता है: कार्य अब रद्द अवस्था में समाप्त नहीं होगा, लेकिन अंदर RanToCompletion। और यह न केवल स्पष्ट राज्य जांच को प्रभावित कर सकता है, बल्कि उपयोग के ContinueWithआधार पर , अधिक सूक्ष्मता से, उदाहरण के साथ, कार्य की रूपरेखा तैयार करता TaskContinuationOptionsहै। मैं कहूंगा कि परहेज ThrowIfCancellationRequestedखतरनाक सलाह है।


1
धन्यवाद! यह ऑनलाइन पाठ, काफी आधिकारिक (पुस्तक "सी # 4.0 इन ए नटशेल"?) का उल्लेख नहीं करता है। क्या आप मुझे "हमेशा" के बारे में एक संदर्भ दे सकते हैं?
फुलप्रूफ

1
यह अभ्यास और अनुभव =) से आता है। मुझे याद नहीं है कि मुझे यह कहां से पता है। मैंने "आपको हमेशा आवश्यकता" का उपयोग किया क्योंकि आप वास्तव में थ्रेड.एबोर्ट () का उपयोग करके बाहर से कार्यकर्ता थ्रेड को बाधित कर सकते हैं, लेकिन यह बहुत बुरा अभ्यास है। वैसे, रद्द करने का उपयोग करके Token.ThrowIfCancellationRequested () भी "अपने आप से रद्द करना" है, बस इसे करने का दूसरा तरीका।
साशा

1
@OleksandrPshenychnyy का मतलब था, जबकि (सच!) को समय के साथ बदल दिया गया था (! यह मददगार था! धन्यवाद!
डग डावसन

1
@ फ़ुलप्रूफ रनिंग कोड को रद्द करने के लिए रनटाइम के लिए कोई सामान्य तरीका नहीं है क्योंकि रनटाइम्स यह जानने के लिए पर्याप्त स्मार्ट नहीं हैं कि एक प्रक्रिया को कहां बाधित किया जा सकता है। कुछ मामलों में केवल एक लूप से बाहर निकलना संभव है, अन्य मामलों में अधिक जटिल तर्क की आवश्यकता होती है, यानी लेनदेन को वापस रोल करना पड़ता है, संसाधनों को जारी करना पड़ता है (जैसे फ़ाइल हैंडल या नेटवर्क कनेक्शन)। यही कारण है कि कुछ कोड लिखने के बिना किसी कार्य को रद्द करने का कोई जादुई तरीका नहीं है। आप जो सोचते हैं वह एक प्रक्रिया को मारने जैसा है, लेकिन यह रद्द नहीं है कि सबसे खराब चीजों में से एक आवेदन के लिए हो सकता है क्योंकि सफाई नहीं हो सकती है।
user3285954

1
यदि आप मैन्युअल रूप से शुरू हो रहे ऑपरेशन को रद्द करने की योजना नहीं बनाते हैं, तो @kosist आप कैंसिलेशनटोकन का उपयोग कर सकते हैं। बेशक जब सिस्टम प्रक्रिया को मार दिया जाता है, तो सब कुछ बाधित हो जाता है और कैंसेलेशनटोकन का इससे कोई लेना-देना नहीं है। तो हाँ, आपको केवल कैंसिलेशनटॉकेन स्रोत बनाना चाहिए यदि आपको ऑपरेशन को रद्द करने के लिए वास्तव में इसका उपयोग करने की आवश्यकता है। आपके द्वारा उपयोग नहीं की जाने वाली कोई चीज़ बनाने में कोई समझदारी नहीं है।
साशा

26

@ BrainSlugs83

आप आँख बंद करके विश्वास नहीं करना चाहिए सब कुछ stackoverflow पर तैनात हैं। जेन्स कोड में टिप्पणी गलत है, पैरामीटर यह नियंत्रित नहीं करता है कि अपवाद फेंके गए हैं या नहीं।

MSDN बहुत स्पष्ट है कि पैरामीटर क्या नियंत्रित करता है, क्या आपने इसे पढ़ा है? http://msdn.microsoft.com/en-us/library/dd321703(v=vs.110).aspx

यदि throwOnFirstExceptionयह सच है, तो एक कॉल तुरंत रद्द करने के लिए कॉल का प्रचार करेगा, शेष कॉलबैक और रद्द करने योग्य कार्यों को संसाधित होने से रोक देगा। यदि throwOnFirstExceptionगलत है, तो यह अधिभार किसी भी अपवादों को एक में फेंक देगा AggregateException, जैसे कि एक अपवाद को फेंकने वाला अन्य पंजीकृत कॉलबैक को निष्पादित होने से नहीं रोकेगा।

चर का नाम भी गलत है क्योंकि रद्द को CancellationTokenSourceस्वयं टोकन नहीं कहा जाता है और स्रोत प्रत्येक टोकन की स्थिति को बदल देता है।


इसके अलावा डॉक्यूमेंटेशन टोकन के प्रस्तावित उपयोग के बारे में दस्तावेज (TAP) पर एक नज़र डालें: docs.microsoft.com/en-us/dotnet/standard/…
एपस्टोन

1
यह बहुत उपयोगी जानकारी है, लेकिन यह बिल्कुल पूछे गए प्रश्न का उत्तर नहीं देता है।
11nallan11

16

आप रद्दीकरण टोकन के साथ एक टास्क बना सकते हैं, जब आप गोटो बैकग्राउंड को एप करते हैं तो आप इस टोकन को रद्द कर सकते हैं।

आप इसे 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);

अन्य समाधान Xamarin.Forms में उपयोगकर्ता टाइमर है, जब ऐप गोटो पृष्ठभूमि https://xamarinhelp.com/xamarin-forms-timer/


10

आप अपवाद को संभालने के बिना उपयोग कर सकते हैं ThrowIfCancellationRequested!

का उपयोग ThrowIfCancellationRequestedएक Task(नहीं Thread) के भीतर से इस्तेमाल किया जा करने के लिए है । जब एक के भीतर उपयोग किया जाता है Task, तो आपको स्वयं अपवाद को संभालने की ज़रूरत नहीं है (और अनहेल्ड अपवाद त्रुटि प्राप्त करें)। यह छोड़ने में परिणाम होगा Task, और Task.IsCancelledसंपत्ति ट्रू होगी। कोई अपवाद हैंडलिंग की जरूरत है।

अपने विशिष्ट मामले में, बदलने के Threadएक करने के लिए Task

Task t = null;
try
{
    t = Task.Run(() => Work(cancelSource.Token), cancelSource.Token);
}

if (t.IsCancelled)
{
    Console.WriteLine("Canceled!");
}

आप उपयोग क्यों कर रहे हैं t.Start()और क्या नहीं Task.Run()?
Xander Luciano

1
@XanderLuciano: इस उदाहरण में कोई विशेष कारण नहीं है, और टास्क.रुण () बेहतर विकल्प होगा।
टाइटस

5

आपको CancellationTokenटास्क को पास करना होगा, जो समय-समय पर टोकन को मॉनिटर करता है कि क्या रद्द करने का अनुरोध किया गया है।

CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;  
Task task = Task.Run(() => {     
  while(!token.IsCancellationRequested) {
      Console.Write("*");         
      Thread.Sleep(1000);
  }
}, token);
Console.WriteLine("Press enter to stop the task"); 
Console.ReadLine(); 
cancellationTokenSource.Cancel(); 

इस स्थिति में, रद्द करने का अनुरोध करने पर ऑपरेशन समाप्त हो Taskजाएगा और उसके पास एक RanToCompletionराज्य होगा। यदि आप स्वीकार करना चाहते हैं कि आपका कार्य रद्द कर दिया गया है , तो आपको ThrowIfCancellationRequestedएक OperationCanceledExceptionअपवाद फेंकने के लिए उपयोग करना होगा ।

Task task = Task.Run(() =>             
{                 
    while (!token.IsCancellationRequested) {
         Console.Write("*");                      
        Thread.Sleep(1000);                 
    }           
    token.ThrowIfCancellationRequested();               
}, token)
.ContinueWith(t =>
 {
      t.Exception?.Handle(e => true);
      Console.WriteLine("You have canceled the task");
 },TaskContinuationOptions.OnlyOnCanceled);  

Console.WriteLine("Press enter to stop the task");                 
Console.ReadLine();                 
cancellationTokenSource.Cancel();                 
task.Wait(); 

आशा है कि यह बेहतर समझने में मदद करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.