2010-02-25 15 views
16

से थ्रेड पर एबॉर्ट मेरा सहकर्मी किसी तृतीय-पक्ष .NET लाइब्रेरी का उपयोग कर रहा है जिसके लिए हमारे पास स्रोत कोड नहीं है। हम थ्रेडपूल का उपयोग कर रहे हैं ताकि इस पुस्तकालय में बहुत से धागे बुला सकें, और कभी-कभी धागे में से एक हमेशा के लिए लटका होगा जबकि बाकी के साथ चुपके से चिपकाएंगे।कॉलिंग थ्रेड। थ्रेडपूल

तो हम ऐसे धागे को मारने के लिए भयभीत Thread.Abort का उपयोग करना चाहते हैं। मैंने अपने स्वयं के धागे कताई से पहले यह किया है, लेकिन मैंने कभी थ्रेडपूल का उपयोग नहीं किया है। हम इस तरह प्रत्येक कार्य की शुरुआत के समय को ट्रैक करते हैं:

static Dictionary<Thread, DateTime> started = new Dictionary<Thread, DateTime>(); 

static void DoSomeWork(object foo) 
{ 
    lock(started) 
     started[Thread.CurrentThread] = DateTime.Now; 

    SomeBuggyLibraryThatMightInfiniteLoopOrSomething.callSomeFunction(doo); 

    lock(started) 
     started.Remove(Thread.CurrentThread); 
} 

तो हम ताला और चल धागे से अधिक पुनरावृति और उन्हें मारने के लिए Thread.Abort कॉल कर सकते हैं? और यदि हम करते हैं, तो क्या हमें उस थ्रेडपूल में एक नया धागा जोड़ने की आवश्यकता होगी जिसे हमने अभी मार दिया है, या थ्रेडपूल हमारे लिए हैडल करेगा?

संपादित करें: Thread.Abort के साथ सभी संभावित समस्याओं के बारे में मुझे बहुत जानकारी है। मुझे पता है कि इसे आदर्श रूप से कभी भी उत्पादन कोड में उपयोग नहीं किया जाना चाहिए, और यह आवश्यक रूप से धागे को भी रोक नहीं सकता है, और यदि थ्रेड को लॉक प्राप्त करने के दौरान आप थ्रेड को रोकते हैं, तो आप अन्य धागे, आदि को लटका सकते हैं। लेकिन अभी हम एक तंग समय सीमा पर हैं और हमारे पास यह मानने का सभ्य कारण है कि इस विशेष मामले में, हम पूरी प्रक्रिया को खतरे में डाल दिए बिना Thread.Abort पर कॉल कर सकते हैं, और हम थ्रेडपूल को खत्म करने के लिए इस प्रोग्राम को फिर से लिखना टालना चाहते हैं जब तक हम बिल्कुल नहीं करना है।

तो मैं जो जानना चाहता हूं वह यह है: यह देखते हुए कि हम थ्रेडपूल से संबंधित धागे पर Thread.Abort पर कॉल करेंगे, क्या थ्रेडपूल धागे होने के कारण कोई विशेष समस्याएं हैं, और क्या हमें मैन्युअल रूप से स्पिन करना है नया धागा जिसे मार डाला गया है उसे बदलने के लिए या थ्रेडपूल हमारे लिए ऐसा करेगा?

+0

"[एक ThreadPool धागे छोड़ रहा है] लेकिन खतरनाक है। समय सूचना प्राप्त होने पर रखकर और धागा निरस्त किया गया है, मूल कृति आइटम पहले से ही समाप्त किया जा सकता था ऐसी है कि पूल के धागा पहले से ही कार्य आइटम पर स्थानांतरित हो गया है। आप वांछित व्यक्ति की बजाय उस माध्यमिक कार्य वस्तु को निरस्त कर देंगे, स्वयं को चोट पहुंचाने की दुनिया तक खोलना होगा। "- स्टीफन टब, एमएसडीएन पत्रिका 06-03 – JBSnorro

उत्तर

8

नहीं, आपको थ्रेड पूल में थ्रेड पर अपरोर्ट नहीं करना चाहिए। मेरे स्थानीय परीक्षण से, ऐसा लगता है कि थ्रेडपूल थ्रेड को फिर से बनाता है यदि आप उन्हें रोकते हैं - मैंने 1000 थ्रेड पूल थ्रेड्स को निरस्त कर दिया और यह अभी भी काम कर रहा था। मुझे नहीं पता कि आपको इस व्यवहार पर भरोसा करना चाहिए, लेकिन शायद आप इस मामले में इससे दूर हो सकते हैं। सामान्य रूप से Thread.Abort का उपयोग करने के लिए यह सही तरीका नहीं है।

एक ऐसे फ़ंक्शन को कॉल करने का सही तरीका जिसे आप अच्छी तरह से व्यवहार करने के लिए भरोसा नहीं करते हैं, उसे एक नई प्रक्रिया में शुरू करना और यदि आवश्यक हो तो प्रक्रिया को मारना है।

+0

यह क्यों है? मैं .NET से बहुत परिचित नहीं हूं, तो क्या आप कृपया बता सकते हैं कि थ्रेडपूल धागे सामान्य थ्रेड से अलग कैसे हैं? इसके लायक होने के लिए, मैंने अतीत में धागे को मार दिया है जो थ्रेडपूल का उपयोग नहीं करते समय इस लाइब्रेरी पर लटकते हैं। यह देखते हुए, क्या इस बात पर विश्वास करने का कोई कारण है कि यह Thread.Abort को थ्रेडपूल थ्रेड पर कॉल करने के लिए काम नहीं करेगा? (मुझे पता है कि यह सामान्य रूप से खराब अभ्यास है, लेकिन हम समय सीमा पर हैं और इसमें से अधिकतर को फिर से लिखने का समय नहीं है, इसलिए अभी एक त्वरित सुधार उपयोगी होगा।) –

+0

क्या आप इसे बेहतर समझा सकते हैं? –

+5

@Eli: आपको सामान्य धागे पर थ्रेड.एबॉर्ट को कॉल नहीं करना चाहिए। शुरुआत के लिए, थ्रेड। एबॉर्ट को धागे को समाप्त करने की भी गारंटी नहीं है। भले ही यह सफलतापूर्वक धागे को निरस्त कर देता है, आप नहीं जानते कि आपने किस गड़बड़ी को पीछे छोड़ दिया है या इसे कैसे साफ किया जाए। आप अनजान संसाधनों के साथ समाप्त हो सकता है। यह वास्तव में एक अच्छा विचार नहीं है। –

5

थ्रेड.एबॉर्ट का उपयोग करने की सलाह नहीं दी जाती है, क्योंकि यह आपके एप्लिकेशन को अमान्य स्थिति में छोड़ सकता है। इसका कारण यह है कि जब थ्रेड को रद्द करने की मांग की जाती है, तो उस तृतीय पक्ष पुस्तकालय में लगभग किसी भी संभावित स्थान पर अपवाद उठाया जा सकता है। यह संभव है कि कोड सेगमेंट हैं जो इन एसिंक्रोनस एबॉर्ट्स से निपटने में सक्षम होने के लिए लिखे गए नहीं हैं।

इसलिए आम तौर पर इसे थ्रेड को रद्द करने की सलाह नहीं दी जाती है, ऐसे मेजबान होते हैं जो थ्रेड को निरस्त करने में बहुत आक्रामक होते हैं। उनमें से एक एएसपी.नेट है। जब कोई अनुरोध बहुत लंबा लगता है, तो यह आपके लिए धागे को रोक देगा। तो इस बात को ध्यान में रखते हुए यह कहना मूर्खतापूर्ण है कि "धागे को कभी न छोड़ें"।

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

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

+0

विश्लेषण के लिए धन्यवाद। तो अगर मैं थ्रेडपूल थ्रेड पर थ्रेड। एबॉर्ट कहता हूं, तो क्या मुझे इसे बदलने के लिए एक नया थ्रेड बनाना होगा, या थ्रेडपूल देखेंगे कि थ्रेड निकल गया है और स्वचालित रूप से नया बना सकता है? –

+1

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

3

मार्क को क्या कहना है, यह स्पष्ट करने के लिए, अगर आप थ्रेड कहते हैं। एबॉर्ट आपको पता नहीं है कि यह ThreadAbortException की विशेष प्रकृति के कारण तीसरे पक्ष के घटक में कहां छोड़ेगा - यह FileStream उदाहरण के लिए खुला हो सकता है।

मैं व्यक्तिगत रूप से धागे अपने आप बन जाएगा, एक IList या कतार में संदर्भित (ThreadPool बेहतर आग और भूल या WaitHandles के लिए अनुकूल है के रूप में), और यदि आप एक धागा है कि 3 पार्टी घटक प्रतिसाद नहीं इस्तेमाल कर रहा है निरस्त किया जा रहा लगता है पर निर्भर करता है यह खतरनाक नहीं है, Abort यह।

आप 3 पार्टी पुस्तकालय एक System.Threading.Timer

वैकल्पिक रूप से

का उपयोग कर समय की एक निर्धारित राशि के बाद, एक अस्वीकार्य राज्य में छोड़ सकते हैं Join धागे कि एक के बाद एक पूरा नहीं किया है, रद्द किया लगता है कि अगर

थ्रेडपूल का उपयोग करने के साथ चिपकने के लिए, आप इसके बजाय इस Smart Thread Pool का उपयोग कर सकते हैं।

तीसरे पक्ष के घटक परावर्तक का उपयोग कर रिवर्स इंजीनियर और वास्तव में यह asynchroneous बनाने के लिए अवरुद्ध कॉल को ठीक:

1

आप एक और विकल्प (जो मैं अगर मैं मेरे सामने एक नि: शुल्क दिन था ले जाएगा) है।

+0

मैं मानता हूं कि यह एक बेहतर समाधान होगा, लेकिन दुर्भाग्य से हमारे पास अभी इसके लिए समय नहीं है। शायद जब यह परियोजना खत्म हो गई हो। –

+1

मुझे लगता है कि आप तीसरे पक्ष के कोड में बस दौड़ की स्थिति में भाग ले सकते हैं। क्या आप इस एपीआई पर पारस्परिक रूप से अनन्य कॉल करने का प्रयास कर सकते हैं? –

+0

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

3

स्टीफन टब द्वारा 'Abortable Thread Pool' पढ़ें। वह एक निरस्त थ्रेड पूल के लिए स्रोत कोड प्रदान करता है। यह एक दिलचस्प पढ़ा है।

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

ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem)); 

HandleItem(...) { 
... 
_threads.Add(item, Thread.CurrentThread); 
... 
} 

वह एक शब्दकोश का उपयोग करता है, धागे के लिए अपने WorkItems लिंक करने के लिए एक उपयोगकर्ता एक धागा यह एक नज़र अप करता है और रद्द करने के लिए चाहता है जब रद्द कि विशेष रूप से धागा।

Dictionary<WorkItem, Thread>() _threads = New Dictionary<WorkItem, Thread>(); 

http://msdn.microsoft.com/en-us/magazine/cc163644.aspx

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