2012-05-27 10 views
8

मुझे लगता है कि मैंने टीपीएल में एक गंभीर बग देखा है। मुझे यकीन नहीं है। मैंने अपने सिर को खरोंचने में बहुत समय बिताया और व्यवहार को समझ नहीं पाया। क्या कोई मदद कर सकता है?टीपीएल में बग - टास्ककंटिन्यूशनऑप्शन। सिंक्रनाइज़ करें?

क्या मेरी परिदृश्य है:

  1. मुझे लगता है कि साधारण चीज़ करने वाला कार्य बनाएँ। कोई अपवाद नहीं आदि
  2. मैं निष्पादन सिंक्रोनस सेट के साथ एक निरंतरता पंजीकृत करता हूं। यह एक ही धागे पर होना चाहिए।
  3. मैं डिफ़ॉल्ट कार्यपत्रक (थ्रेडपूल) पर कार्य शुरू करता हूं। शुरुआती धागा आगे बढ़ता है और इसके लिए इंतजार कर रहा है।
  4. कार्य शुरू होता है। गुजरता।
  5. निरंतरता कार्य के समान थ्रेड पर शुरू होती है (पिछले कार्य को पूरा करने के लिए!) और अंतहीन पाश में प्रवेश करती है।
  6. प्रतीक्षा धागे के साथ कुछ भी नहीं होता है। आगे जाना नहीं चाहता। प्रतीक्षा पर अटक गया। मैंने डीबगर में चेक किया है, कार्य RunToCompletion है।

मेरा कोड यहां है। किसी भी मदद की सराहना करें!

// note: using new Task() and then Start() to avoid race condition dangerous 
// with TaskContinuationOptions.ExecuteSynchronously flag set on continuation. 

var task = new Task(() => { /* just return */ }); 
task.ContinueWith(
    _task => { while (true) { } /* never return */ }, 
    TaskContinuationOptions.ExecuteSynchronously); 

task.Start(TaskScheduler.Default); 
task.Wait(); // a thread hangs here forever even when EnterEndlessLoop is already called. 
+0

मुझे यह भी लगता है कि यह एक बग है। यहां प्रलेखन पृष्ठ है: http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskcontinuationoptions.aspx यह दुर्भाग्यवश, इस मामले के बारे में कुछ भी नहीं कहता है। – usr

+0

कोई भी मौका आप कोड स्निपेट का विस्तार कर सकते हैं, इसलिए यह दूसरों के लिए प्रतिलिपि बनाने और चलाने के लिए पर्याप्त है? –

+0

@usr - यह कहता है "केवल बहुत ही कम चलने वाली निरंतरता को समकालिक रूप से निष्पादित किया जाना चाहिए।" :) मैं सहमत हूं कि यह एक बग है, यद्यपि। –

उत्तर

5

आपकी ओर से कनेक्ट होने पर एक बग दायर - उम्मीद है कि ठीक है :)

https://connect.microsoft.com/VisualStudio/feedback/details/744326/tpl-wait-call-on-task-doesnt-return-until-all-continuations-scheduled-with-executesynchronously-also-complete

मैं मानता हूँ कि यह एक बग है, बस एक कोड का टुकड़ा है कि बिना इस मुद्दे से पता चलता पोस्ट करने के लिए करना चाहता था एक 'अंतहीन' प्रतीक्षा करें। बग यह है कि एक निष्पादन सिंक्रनाइज़ली का मतलब है कि पहले कार्य पर प्रतीक्षा कॉल तब तक वापस नहीं आती जब तक निष्पादन सिंक्रोनस निरंतरताएं पूरी नहीं हो जातीं।

नीचे स्निपेट चलाने से पता चलता है कि यह 17 सेकंड तक प्रतीक्षा करता है (इसलिए सभी 3 को केवल पहले की बजाय पूरा करना था)। यह वही है कि तीसरा कार्य पहले या दूसरे को निर्धारित किया गया है (इसलिए यह निष्पादन सिंक्रनाइज़ रूप से इस तरह के कार्यों के पेड़ के माध्यम से जारी रहेगा)।

void Main() 
{ 
    var task = new Task(() => Thread.Sleep(2 * 1000)); 
    var secondTask = task.ContinueWith(
     _ => Thread.Sleep(5 * 1000), 
     TaskContinuationOptions.ExecuteSynchronously); 
    var thirdTask = secondTask.ContinueWith(
     _ => Thread.Sleep(10 * 1000), 
     TaskContinuationOptions.ExecuteSynchronously); 

    var stopwatch = Stopwatch.StartNew(); 
    task.Start(TaskScheduler.Default); 
    task.Wait(); 
    Console.WriteLine ("Wait returned after {0} seconds", stopwatch.ElapsedMilliseconds/1000.0); 
} 

केवल एक चीज मुझे लगता है कि यह जानबूझकर (और इसलिए कोड बग से कोई दस्तावेज़ बग अधिक) हो सकता है कि बनाता है Stephen's comment in this blog post है:

ExecuteSynchronously एक अनुकूलन को चलाने के लिए एक अनुरोध है पूर्ववर्ती कार्य कार्य पूरा करने वाले कार्य को जारी रखने के लिए निरंतर चल रहा है पूर्ववर्ती के संक्रमण के हिस्से के रूप में निरंतर चल रहा है इनल राज्य

0

तो यह पता चला है कि यह वास्तव में एक बग है। मुझे लगता है कि हर कोई सहमत है। यदि यह इस तरह व्यवहार करने का इरादा था, तो एपीआई और दस्तावेज़ अत्यधिक भ्रामक प्रतीत होते हैं।

मेरे द्वारा उपयोग किए जाने वाले काम को मैन्युअल रीसेट इवेंटस्लिम का उपयोग करना है।

var eventSlim = new ManualResetEventSlim(false); 
var task = new Task(() => { eventSlim.Set(); }); 
task.ContinueWith(
    _task => { while (true) { } /* never return */ }, 
    TaskContinuationOptions.ExecuteSynchronously); 

task.Start(TaskScheduler.Default); 
eventSlim.Wait(); 

इस पर एक नज़र रखने के लिए सभी को धन्यवाद! और सभी टिप्पणियों के लिए।

सम्मान।

3

जब आप task inlining पर विचार करते हैं तो यह व्यवहार समझ में आता है। कार्य को निष्पादन शुरू करने से पहले Task.Wait पर कॉल करने पर, शेड्यूलर इसे इनलाइन करने का प्रयास करेगा, यानी इसे उसी थ्रेड पर चलाएं जिसे Task.Wait कहा जाता है। यह समझ में आता है - कार्य को निष्पादित करने के लिए थ्रेड का पुन: उपयोग करते समय कार्य के लिए प्रतीक्षा करने वाले धागे को बर्बाद क्यों करें?

अब, जब ExecuteSynchronously निर्दिष्ट है, शेड्यूलर को पूर्ववर्ती कार्य के समान थ्रेड पर निरंतरता निष्पादित करने का निर्देश दिया जाता है - जो इनलाइनिंग के मामले में मूल कॉलिंग थ्रेड है।

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

task.Wait(new CancellationTokenSource().Token); //This won't wait for the continuation 

अंत में ध्यान दें कि इनलाइनिंग की गारंटी नहीं है। मेरी मशीन पर, ऐसा नहीं हुआ क्योंकि यह कार्य Wait कॉल से पहले ही शुरू हो चुका है, इसलिए मेरा Wait कॉल अवरुद्ध नहीं हुआ। यदि आप एक पुनरुत्पादित ब्लॉक चाहते हैं, तो Task.RunSynchronously पर कॉल करें।

संबंधित मुद्दे