6

में एक डेडलॉक टास्क को मारना मैं Task Parallel Library का उपयोग करना शुरू करना चाहता हूं, क्योंकि यह अनुशंसित फ्रेमवर्क एसिंक्रोनस ऑपरेशंस करने के लिए आगे बढ़ रहा है। एक चीज जिसे मैं ढूंढने में सक्षम नहीं हूं, वह जबरदस्त गर्भपात का कोई साधन है, जैसे थ्रेड.एबॉर्ट प्रदान करता है।.NET 4 TPL

मेरी विशेष चिंता यह है कि मैं ऐसे कोड चलाने वाले कार्यों को शेड्यूल करता हूं जिन्हें मैं पूरी तरह से भरोसा नहीं करना चाहता हूं। विशेष रूप से, मैं यह सुनिश्चित नहीं कर सकता कि यह अविश्वसनीय कोड डेडलॉक नहीं होगा और इसलिए मैं निश्चित नहीं हो सकता कि यदि इस कोड का उपयोग करने वाला कार्य I शेड्यूल कभी पूरा हो जाएगा। मैं सच्चे ऐपडोमेन अलगाव से दूर रहना चाहता हूं (मार्शलिंग के ऊपरी हिस्से और जटिलता के कारण), लेकिन मैं भी एक कार्य धागा को चारों ओर लटका नहीं देना चाहता हूं। क्या टीपीएल में ऐसा करने का कोई तरीका है?

उत्तर

9

ऐसा करने का तरीका रद्दीकरण टोकन और नया रद्दीकरण मॉडल के साथ है। नया रद्दीकरण मॉडल कई प्रकारों में .NET Framework में एकीकृत है। सबसे महत्वपूर्ण सिस्टम हैं। थ्रेडिंग। कार्य, सिस्टम .Treading.Tasks.Task, System.Threading.Tasks.Task और System.Linq.ParallelEnumerable।

यहां आपकी समस्या का एक उदाहरण है। यह कोड हमेशा डेडलॉक होगा क्योंकि कॉलिंग कोड पहले लॉक लेता है और फिर मृतक कार्य उसी लॉक को प्राप्त करने का प्रयास करता है।

public void Example() 
{ 
    object sync = new Object(); 
    lock (sync) 
    { 
     CancellationTokenSource canceller = new CancellationTokenSource(); 
    ManualResetEvent started = new ManualResetEvent(false); 
     Task deadlocked = Task.Factory.StartNew(() => 
      { 
      started.Set(); 
       // EVIL CODE: This will ALWAYS deadlock 
       lock(sync) { }; 
      }, 
      canceller.Token); 

     // Make sure task has started. 
    started.WaitOne(); 

     canceller.Cancel(); 

     try 
     { 
      // Wait for task to cancel. 
      deadlocked.Wait(); 
     } 
     catch (AggregateException ex) 
     { 
      // Ignore canceled exception. SIMPLIFIED! 
      if (!(ex.InnerException is TaskCanceledException)) 
       throw; 
     } 
    } 
} 

टीपीएल में कार्य रद्दीकरण सहकारी है। दूसरे शब्दों में यह हमेशा डेडलॉक होगा क्योंकि रद्दीकरण टोकन को रद्द करने के लिए कुछ भी सेट नहीं किया जाता है क्योंकि टास्क थ्रेड लॉक हो जाता है।

इस के चारों ओर एक तरीका नहीं है लेकिन यह अभी भी अविश्वसनीय कोड के लेखकों पर निर्भर करता है सही काम करने के लिए:

public static void Example2() 
{ 
    Mutex sync = new Mutex(true); 

    CancellationTokenSource canceller = new CancellationTokenSource(); 
    bool started = false; 

    Task deadlocked = Task.Factory.StartNew(() => 
     { 
      started = true; 
      // EVIL CODE: This will ALWAYS deadlock 
      WaitHandle.WaitAny(new WaitHandle[] { canceller.Token.WaitHandle, sync }); 
     }, 
     canceller.Token); 

    // Make sure task has started. 
    while (!started) { } 

    canceller.Cancel(); 

    try 
    { 
     // Wait for task to cancel. 
     deadlocked.Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     // Ignore canceled exception. SIMPLIFIED! 
     if (!(ex.InnerException is TaskCanceledException)) 
      throw; 
    } 
} 

अंक नोट करने के लिए; रद्दीकरण सहकारी है। आप एक संभाल पाने के लिए टोकन.WaitHandle का उपयोग कर सकते हैं और अन्य सिंक्रनाइज़ेशन primitives के हैंडल (एस) के साथ इसके साथ इंतजार कर सकते हैं। म्यूटेक्स मॉनीटर (या लॉक) से बहुत धीमा है।

वास्तव में यदि आप कोऑपरेटिव रद्दीकरण को लागू करने के लिए पर्याप्त कोड के लेखक पर भरोसा नहीं करते हैं तो मैं एक ही थ्रेड पर अपने ऐपडोमेन के अंदर दौड़ने की संवेदना पर सवाल उठाऊंगा।

अधिक विस्तार के लिए देखें:

http://msdn.microsoft.com/en-us/library/dd997364.aspx

http://msdn.microsoft.com/en-us/library/dd537607.aspx

http://msdn.microsoft.com/en-us/library/ee191552.aspx

+0

धन्यवाद, यह उपयोगी जानकारी है। हालांकि, मैं इस धारणा के तहत था कि रद्दीकरण अनुरोध को सुनने के लिए कार्य पर निर्भर है और यदि आप पूरी तरह से पूरा नहीं कर पा रहे हैं तो ऑपरेशन कैंक्शनल अपवाद को अपने आप पर फेंक दें। जब मैं आज दोपहर का मौका मिलता हूं तो मैं आपका कोड आज़माउंगा। –

+0

पहले लिंक से, "श्रोताओं को मतदान, कॉलबैक पंजीकरण, या प्रतीक्षा हैंडल पर प्रतीक्षा करके रद्दीकरण अनुरोधों के बारे में अधिसूचित किया जा सकता है।" तो प्रभावी ढंग से कार्य। प्रतीक्षा सुनने के कारण होता है। –

+0

देखें: http://stackoverflow.com/questions/2293976/how-and-if-to-write-a-single-consumer-queue-using-the-task-parallel-library/2779208#2779208 के उदाहरण के लिए रद्दीकरण की जांच करने और इसका जवाब देने के लिए IsCancellationRequested का उपयोग करना। –

-4

आप बस Task.Wait(timespanToWait) पर कॉल करें।

यदि कार्य निर्दिष्ट समय के बाद पूरा नहीं हुआ है तो इसे रद्द कर दिया गया है।

+0

धन्यवाद। यह दस्तावेज़ीकरण से बिल्कुल स्पष्ट नहीं था, लेकिन जब आप कार्यों को निर्धारित और प्रबंधित करने के तरीके के बारे में किसी भी विवरण से आपको इन्सुलेट करते हुए कार्य के बारे में सोचते हैं तो यह समझ में आता है। क्या आप जानते हैं कि मुझे सुरक्षित रूप से कार्य का निपटान करने से पहले प्रतीक्षा प्रतीक्षा के बाद मुझे कुछ खास करना होगा? –

+11

यह उत्तर नहीं है। रुको() बस यही करेगा, प्रतीक्षा करें। यह कार्य को रद्द/निरस्त नहीं करेगा। –

0

दान मुझे लगता है कि Task.Wait (timeout) न इस कार्य को रद्द कर देंगे, वहाँ अधिभार Task.Wait (टाइमआउट, cancelationToken) है, लेकिन यह केवल task.Wait पर OperationCanceledException फेंकता है जब टोकन संकेत है।

कार्य। केवल कार्य पूरा होने तक या केवल टाइमआउट समाप्त होने तक ही ब्लॉक करें, यह कार्य को रद्द या रद्द नहीं करता है। तो थ्रेडपूल में लटका हुआ कार्य खड़ा रहेगा। आप अनधिकृत कार्य (अमान्य ऑपरेशन) का निपटान नहीं कर सकते हैं।

इम आवेदन की एक ही तरह writting के रूप में आप और मैं अपने taskScheduler की अनुमति देता है जो छोड़ रहा है (और ThreadPool का उपयोग नहीं कर रहा है :() लिखा।

लेकिन कैसे के बारे में आप इस समस्या का समाधान बहुत ही उत्सुक im। जवाब दें मेरे लिए

+0

आगे विचार करने पर, मैंने फैसला किया कि यदि कोई डेडलॉक हो सकता है, तो थ्रेड। एबॉर्ट वास्तव में केवल अंतर्निहित समस्या का मुखौटा कर रहा है, क्योंकि राज्य पहले से ही दूषित हो चुका है। इस प्रकार, मैं घातक होने की विफलता पर विचार कर रहा हूं (ऑपरेटर के पास प्रतीक्षा रखने या आवेदन को समाप्त करने का विकल्प है)। यह मेरे ऐप के लिए पर्याप्त है क्योंकि यह मिशन महत्वपूर्ण नहीं है; यदि ऐप मिशन महत्वपूर्ण था, तो मुझे आंशिक रूप से भरोसेमंद कोड के लिए ऐपडोमेन्स या एक अलग होस्टिंग प्रक्रिया का उपयोग करने के लिए माइग्रेट करना होगा। –

+0

दान, मुझे लगता है कि इस बारे में सोचने का यह सही तरीका है। Thread.Abort निश्चित रूप से एक समाधान नहीं है। यह आपके एप्लिकेशन को अज्ञात स्थिति में छोड़ सकता है। –