2013-12-17 8 views
6

लोड के नाम पर आईएआई यूआई बटन है। यह एक थ्रेड पैदा करता है, जो बदले में एक कार्य को जन्म देता है। कार्य पर एक प्रतीक्षा है, और यदि यह समाप्त हो जाता है तो कार्य रद्द हो जाता है। लोड बटन अक्षम नहीं है, और उपयोगकर्ता इसे कई बार क्लिक कर सकता है। प्रत्येक बार जब यह पिछले कार्य पर क्लिक किया जाता है तो उसे हटाया जाना चाहिए।रद्दीकरण टोकन और रद्दीकरण टोकन स्रोत- इसका उपयोग कैसे करें?

मुझे उलझन में आ रहा है कि मुझे कैनसेलेशन टोकनसोर्स और रद्दीकरण टोकन का उपयोग कैसे करना चाहिए। मधुमक्खी कोड है..क्या आप कृपया इसका सुझाव दें कि इसका उपयोग कैसे करें और क्या नीचे के उपयोग में कोई समस्या है? कोई Async कृपया के रूप में हम अभी तक नहीं हैं।

CancellationTokenSource _source = new CancellationTokenSource(); 
     public void OnLoad() 
     { 
      //Does this cancel the previously spawned task? 
      _source.Cancel(); 
      _source.Dispose(); 
      _source = new CancellationTokenSource(); 
      var activeToken = _source.Token; 
      //Do I need to do the above all the time or is there an efficient way? 

      Task.Factory.StartNew(() => 
       { 
        var child = Task.Factory.StartNew(() => 
         { 
          Thread.Sleep(TimeSpan.FromSeconds(20)); 
          activeToken.ThrowIfCancellationRequested(); 
         }, activeToken); 

        if (!child.Wait(TimeSpan.FromSeconds(5))) 
        { 
         _source.Cancel(); 
        } 
       }); 
     } 

नोट मैं किसी भी पहले से पैदा की कार्य रद्द करने की आवश्यकता है, और हर पैदा की कार्य समय समाप्त होना चाहिए।

+0

मुझे लगता है कि वहाँ एक विधि में बनाया के बाद एक टोकन रद्द करने के लिए एक निश्चित टाइमआउट। – CodesInChaos

+0

http://stackoverflow.com/a/16607800/34397 – SLaks

+0

@ स्लाक्स- यह काम नहीं करेगा जैसा कि मैं .NET 4.0 – Mike

उत्तर

5

सबसे पहले, यदि आप विजुअल स्टूडियो 2012+ का उपयोग कर रहे हैं तो आप async और अन्य .NET 4.0 प्रोजेक्ट के लिए अन्य उन्नत कार्यक्षमता के लिए समर्थन जोड़ने के लिए Microsoft.Bcl.Async पैकेज जोड़ सकते हैं।

यदि आप विजुअल स्टूडियो 2010 का उपयोग कर रहे हैं, तो आप WithTimeout विस्तार विधि का उपयोग कर सकते हैं जो समानांतर एक्सटेंशन एक्सटेंशन पुस्तकालय के साथ आता है। विधि मूल कार्य को टास्क कॉम्प्लेशनसोर्स और एक टाइमर के साथ लपेटती है जो SetCancelled को समाप्त होने पर कॉल करती है।

कोड here है लेकिन वास्तविक विधि सरल है: सही अपने कार्य को बनाने के बाद

/// <summary>Creates a new Task that mirrors the supplied task but that 
    /// will be canceled after the specified timeout.</summary> 
    /// <typeparam name="TResult">Specifies the type of data contained in the 
    /// task.</typeparam> 
    /// <param name="task">The task.</param> 
    /// <param name="timeout">The timeout.</param> 
    /// <returns>The new Task that may time out.</returns> 
    public static Task<TResult> WithTimeout<TResult>(this Task<TResult> task, 
                  TimeSpan timeout) 
    { 
     var result = new TaskCompletionSource<TResult>(task.AsyncState); 
     var timer = new Timer(state => 
         ((TaskCompletionSource<TResult>)state).TrySetCanceled(), 
         result, timeout, TimeSpan.FromMilliseconds(-1)); 
     task.ContinueWith(t => 
     { 
      timer.Dispose(); 
      result.TrySetFromTask(t); 
     }, TaskContinuationOptions.ExecuteSynchronously); 
     return result.Task; 
    } 

आप इसका इस्तेमाल कर सकते हैं:

var myTask=Task.Factory.StartNew(()=>{...}) 
      .WithTimeout(TimeSpan.FromSeconds(20)); 

सामान्य तौर पर, आप व्यवहार आपके द्वारा चाहते हैं बना सकते हैं आपके द्वारा सेट की गई घटनाओं या मानदंडों के जवाब में एक SetCospletionSource को अपने SetResult, SetCancelled विधियों को कॉल करना।

0

आपके कोड में कुछ गलतियां हैं जो चीजों को भ्रमित करती हैं।

सबसे पहले, आप कार्य के बजाय थ्रेड स्लीप का उपयोग कर रहे हैं। डेले या कुछ अन्य टाइमर-आधारित विधि (यदि आपके पास कार्य तक पहुंच नहीं है तो मैं दृढ़ता से स्वयं लिखने की सलाह देता हूं। डेले)। नींद एक अवरुद्ध प्रतीक्षा है और रद्द टोकन पर सशर्त नहीं किया जा सकता है। नतीजा यह है कि ऑपरेशन रद्द होने पर भी बहुमूल्य थ्रेड पूल धागे को कई सेकंड के लिए बंधक बना दिया जा रहा है। इसका परिणाम बाद के बटनों के बाद के बटन प्रेस के प्रभावों के परिणामस्वरूप हो सकता है।

दूसरा, प्रतीक्षा आप _source रद्द कर रहे हैं के अंत में, लेकिन इस वर्तमान स्रोत नहीं समय बटन दबाया गया था पर मूल्य की _value को दर्शाता है। इससे पहले बटन प्रेस बाद में बटन प्रेस प्रभाव को रद्द कर देंगे।

तीसरा, आप एक थ्रेड पर रद्द टोकन स्रोत का निपटारा कर रहे हैं जबकि इसे दूसरे पर रद्द करने के लिए रेसिंग करते हैं। आप भाग्यशाली हैं कि आप ऑब्जेक्ट डिस्पोजेड अपवाद नहीं प्राप्त कर रहे हैं।

चौथा, इस तरह की स्थिति में एसिंक का उपयोग करना आदर्श होगा। आपने बताया कि आप केवल नेट 4.0 पर थे।

पहले तीन बातें फिक्सिंग करना चाहिए के बारे में तर्क करने के लिए आसान हो रहा है:

CancellationTokenSource _prevSource = new CancellationTokenSource(); 
public void OnButtonPress() { 
    var curSource = new CancellationTokenSource(); 
    _prevSource.Cancel(); 
    _prevSource = curSource; 

    MyCustomDelay(TimeSpan.FromSeconds(5), curSource.Token).ContinueWith(t => { 
     curSource.Cancel(); 
    }, TaskContinuationOptions.OnlyOnRanToCompletion); 

    var r = MyCustomDelay(TimeSpan.FromSeconds(20), curSource.Token).ContinueWith(t => { 
     curSource.ThrowIfCancellationRequested(); 
    }, TaskContinuationOptions.OnlyOnRanToCompletion); 
    // after 5 seconds the token r's delay is conditions on is cancelled 
    // so r is cancelled, due to the continuation specifying OnlyOnRanToCompletion 
    // the ThrowIfCancellationRequested line won't be executed 
    // although if we removed the cancel-after-5-seconds bit then it would be 
} 
+1

.NET 4, कोई कार्य नहीं है। डेले –

+0

@ पानागियोटिस मैंने इसे टाइमर के साथ कार्यान्वित करने के लिए संशोधित करने के लिए संशोधित किया। अवरुद्ध करने की लागत इसे कार्यान्वित करने लायक बनाता है। –

2

यह यह करना होगा:

private CancellationTokenSource _cancelTasks; 

    // this starts your process 
    private void DoStuff() 
    { 
     _cancelTasks = new CancellationTokenSource(); 

     var task = new Task(() => { /* your actions here */ }, _cancelTasks.Token); 
     task.Start(); 

     if (!task.Wait(5000)) _cancelTasks.Cancel(); 
    } 
संबंधित मुद्दे