क्या .NET में ... मौजूद है?


385

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

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

bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }

और क्योंकि Monitor.Enterऔर Monitor.Exitचिह्नित हैं extern। ऐसा प्रतीत होता है कि .NET कुछ ऐसी प्रक्रिया करता है जो थ्रेड्स को सिस्टम घटकों के संपर्क में आने से बचाता है जो इस तरह का प्रभाव डाल सकते हैं, लेकिन यह विशुद्ध रूप से सट्टा है और शायद सिर्फ इस तथ्य पर आधारित है कि मैंने "ज़ोंबी थ्रेड्स" के बारे में कभी नहीं सुना है। इससे पहले। इसलिए, मुझे उम्मीद है कि मुझे इस पर कुछ प्रतिक्रिया मिल सकती है:

  1. क्या मैंने यहाँ जो समझाया है, उससे कहीं अधिक एक "ज़ोंबी थ्रेड" की स्पष्ट परिभाषा है?
  2. क्या ज़ोंबी थ्रेड्स .NET पर हो सकते हैं? (क्यों नहीं?)
  3. यदि लागू हो, तो मैं .NET में एक ज़ोंबी थ्रेड के निर्माण को कैसे मजबूर कर सकता हूं?
  4. यदि लागू हो, तो मैं .NET में एक ज़ोंबी थ्रेड परिदृश्य को जोखिम में डाले बिना लॉकिंग का लाभ कैसे उठा सकता हूं?

अपडेट करें

मैंने दो साल पहले यह सवाल पूछा था। आज यह हुआ:

ऑब्जेक्ट एक ज़ोंबी अवस्था में है।


8
क्या आपको यकीन है कि आपके सह-साथी गतिरोध के बारे में बात नहीं करते हैं ??
एंड्रियास नीडरमेयर

10
@AndreasNiedermair - मुझे पता है कि गतिरोध क्या है और यह स्पष्ट रूप से उस शब्दावली के दुरुपयोग का मामला नहीं था। बातचीत में डेडलॉकिंग का उल्लेख किया गया था और "ज़ोंबी थ्रेड" से स्पष्ट रूप से अलग था। मेरे लिए, मुख्य अंतर यह है कि एक डेड लॉक में दो-तरफा अन-रिज़ॉल्वेबल निर्भरता होती है जबकि ज़ोंबी थ्रेड एक तरफ़ा होता है, और एक समाप्त प्रक्रिया की आवश्यकता होती है। यदि आप असहमत हैं और सोचते हैं कि इन चीजों को देखने का एक बेहतर तरीका है, तो कृपया समझाएं
स्मार्टकविमैन

19
मुझे लगता है कि शब्द "ज़ोंबी" वास्तव में एक UNIX बैकगाउंड से आता है, जैसा कि "ज़ोंबी प्रक्रिया" में है, सही ??? UNIX में "ज़ोंबी प्रक्रिया" की एक स्पष्ट परिभाषा है: यह एक बच्चे की प्रक्रिया का वर्णन करता है जिसे समाप्त कर दिया गया है, लेकिन जहां बच्चे की प्रक्रिया के माता-पिता को अभी भी कॉल करके waitया (बच्चे के संसाधन) को "जारी" करने की आवश्यकता है waitpid। फिर बच्चे की प्रक्रिया को "ज़ोंबी प्रक्रिया" कहा जाता है। यह भी देखें कि howtogeek.com/119815
hogliux

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

9
"पहले कंप्यूटरों के बाद से, मशीन में हमेशा भूत होते रहे हैं। कोड के यादृच्छिक खंड जो अप्रत्याशित प्रोटोकॉल बनाने के लिए एक साथ समूहीकृत किए गए हैं ..."
क्रिस लाप्लांटे

जवाबों:


242
  • क्या मैंने यहाँ जो समझाया है, उससे कहीं अधिक एक "ज़ोंबी थ्रेड" की स्पष्ट परिभाषा है?

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

  • क्या ज़ोंबी थ्रेड्स .NET पर हो सकते हैं? (क्यों नहीं?)
  • यदि लागू हो, तो मैं .NET में एक ज़ोंबी थ्रेड के निर्माण को कैसे मजबूर कर सकता हूं?

वे निश्चित रूप से करते हैं, देखो, मैंने एक बना दिया है!

[DllImport("kernel32.dll")]
private static extern void ExitThread(uint dwExitCode);

static void Main(string[] args)
{
    new Thread(Target).Start();
    Console.ReadLine();
}

private static void Target()
{
    using (var file = File.Open("test.txt", FileMode.OpenOrCreate))
    {
        ExitThread(0);
    }
}

यह प्रोग्राम एक थ्रेड शुरू करता है Targetजो एक फ़ाइल खोलता है और फिर तुरंत ही उपयोग करके मारता है ExitThreadपरिणामस्वरूप ज़ोंबी थ्रेड कभी भी "test.txt" फ़ाइल को हैंडल जारी नहीं करेगा और इसलिए फ़ाइल तब तक खुली रहेगी जब तक कि प्रोग्राम समाप्त नहीं हो जाता है (आप प्रक्रिया एक्सप्लोरर या इसी तरह की जांच कर सकते हैं)। "Test.txt" के हैंडल को तब तक जारी नहीं किया जाएगा, जब तक GC.Collectइसे कॉल नहीं किया जाता है - यह पता चलता है कि यह एक ज़ोंबी धागा बनाने के लिए जितना मैंने सोचा था उससे भी अधिक कठिन है जो लीक को संभालता है)

  • यदि लागू हो, तो मैं .NET में एक ज़ोंबी थ्रेड परिदृश्य को जोखिम में डाले बिना लॉकिंग का लाभ कैसे उठा सकता हूं?

मैं अभी क्या किया मत करो!

जब तक आपका कोड अपने आप सही तरीके से साफ नहीं हो जाता है ( सुरक्षित संसाधनों के साथ काम करने पर सुरक्षित हैंडल या समकक्ष कक्षाओं का उपयोग करें ), और जब तक आप अजीब और अद्भुत तरीके से धागे को मारने के लिए अपने रास्ते से बाहर नहीं जाते हैं (सबसे सुरक्षित तरीका बस है थ्रेड्स को मारने के लिए - उन्हें अपने आप को सामान्य रूप से समाप्त करने दें, या यदि आवश्यक हो तो अपवादों के माध्यम से), एक ही तरीका है कि आपके पास एक ज़ोंबी धागा जैसा कुछ होने वाला है अगर कुछ बहुत गलत हो गया है (जैसे सीएलआर में कुछ गलत हो जाता है)।

वास्तव में इसका वास्तव में आश्चर्यजनक रूप से एक ज़ोंबी थ्रेड बनाना मुश्किल था (मुझे एक फ़ंक्शन में पी / इनवॉइस करना पड़ा जो कि प्रलेखन में आपको सी के बाहर कॉल नहीं करने के लिए कहता है)। उदाहरण के लिए निम्नलिखित (भयानक) कोड वास्तव में एक ज़ोंबी थ्रेड नहीं बनाता है।

static void Main(string[] args)
{
    var thread = new Thread(Target);
    thread.Start();
    // Ugh, never call Abort...
    thread.Abort();
    Console.ReadLine();
}

private static void Target()
{
    // Ouch, open file which isn't closed...
    var file = File.Open("test.txt", FileMode.OpenOrCreate);
    while (true)
    {
        Thread.Sleep(1);
    }
    GC.KeepAlive(file);
}

कुछ बहुत ही भयानक गलतियाँ करने के बावजूद, "test.txt" के हैंडल को अभी भी बंद कर दिया जाता Abortहै, जिसे कॉल किया जाता है ( फाइनल के हिस्से के रूप में fileजिसके लिए कवर के तहत SafeFileHandle का उपयोग करके इसकी फाइल हैंडल लपेटी जाती है)

C.Evenhuis उत्तर में लॉकिंग उदाहरण संभवतः किसी संसाधन (इस मामले में लॉक) को जारी करने में विफल रहने का सबसे आसान तरीका है जब एक थ्रेड को गैर-अजीब तरीके से समाप्त किया जाता है, लेकिन lockइसके बजाय या तो एक बयान का उपयोग करके आसानी से तय किया जाता है, या एक finallyब्लॉक में रिलीज डाल रहा है ।

यह सभी देखें


3
मुझे याद है कि जब मैंने एक बैकग्राउंडर का उपयोग करके एक्सेल में सामान बचाने के साथ खेला था तो मैंने हर समय सभी संसाधनों को जारी नहीं किया (क्योंकि मैं सिर्फ डिबगिंग आदि को छोड़ देता हूं)। कार्यपालक में मैंने बाद में लगभग 50 एक्सेल प्रक्रियाओं को देखा। क्या मैंने zombieexcelprocesses बनाया?
स्टीफन

3
@ जस्टिन - +1 - शानदार जवाब। मैं ExitThreadहालांकि आपके कॉल को लेकर थोड़ा सशंकित हूं । जाहिर है, यह काम करता है, लेकिन यह यथार्थवादी परिदृश्य की तुलना में एक चतुर चाल की तरह महसूस करता है। मेरा एक लक्ष्य यह सीखना है कि क्या नहीं करना चाहिए ताकि मैं गलती से .NET कोड के साथ ज़ोंबी थ्रेड न बना सकूं। मैं शायद यह समझ सकता था कि C ++ कोड को कॉल करना जो .NET कोड से उस मुद्दे को उत्पन्न करने के लिए जाना जाता है, वांछित प्रभाव पैदा करेगा। आप स्पष्ट रूप से इस सामान के बारे में बहुत कुछ जानते हैं। क्या आप किसी भी अन्य मामलों के बारे में जानते हैं (संभवतः अजीब है, लेकिन अजीब नहीं है कि एक ही परिणाम के साथ अनजाने में कभी ऐसा न हो)?
स्मार्टक्वेमैन

3
तो जवाब है 'c # 4 में नहीं', सही है? यदि आपको ज़ोंबी धागा प्राप्त करने के लिए सीएलआर से बाहर कूदना है, तो यह एक .net समस्या की तरह नहीं लगता है।
गुस्सोर

4
@Stefan मैं लगभग निश्चित रूप से नहीं कहूंगा। मैंने वह किया है जो आपने बहुत बार वर्णित किया है। एक्सेल प्रक्रियाएं लाश नहीं हैं क्योंकि वे अभी भी चल रहे हैं हालांकि सामान्य यूआई के माध्यम से तुरंत सुलभ नहीं हैं। आपको GetObject पर कॉल के माध्यम से उन्हें पुनः प्राप्त करने में सक्षम होना चाहिए । Set excelInstance = GetObject(, "Excel.Application")
डैनियल

7
"परिणामी ज़ोंबी थ्रेड कभी भी" test.txt "फ़ाइल को हैंडल जारी नहीं करेगा और इसलिए फ़ाइल तब तक खुली रहेगी जब तक कि प्रोग्राम समाप्त नहीं हो जाता" गलत है। छोटा सा प्रमाण: `स्टेटिक शून्य मेन (स्ट्रिंग [] आर्ग्स) {नया थ्रेड (GcCollect) .Start (); नया धागा (लक्ष्य)। स्टार्ट (); Console.ReadLine (); } निजी स्थिर शून्य लक्ष्य () {प्रयोग (var file = File.Open ("test.txt", FileMode.OpenOrCreate)) {ExitThread (0); }} निजी स्थिर शून्य GcCollect () {जबकि (सच) {Thread.Sleep (10000); GC.Collect (); }} `
Sinix

46

मैंने अपना उत्तर थोड़ा साफ कर दिया है, लेकिन संदर्भ के लिए मूल नीचे छोड़ दिया है

यह पहली बार है जब मैंने इस शब्द के बारे में सुना है ताकि मैं मान लूं कि इसकी परिभाषा क्या है:

एक धागा जो अपने सभी संसाधनों को जारी किए बिना समाप्त हो गया है

तो उस परिभाषा को देखते हुए, फिर हाँ, आप ऐसा कर सकते हैं। जैसे कि अन्य भाषाओं (C / C ++, java) के साथ।

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

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

मूल उत्तर Zombies मौजूद है, तो आप उचित सूत्रण कोड लिखने नहीं है सकते हैं। अन्य भाषाओं जैसे C / C ++ और Java के लिए भी यही सही है। लेकिन यह .NET में थ्रेडेड कोड न लिखने का एक कारण नहीं है।

और किसी भी अन्य भाषा के साथ की तरह, कुछ का उपयोग करने से पहले कीमत पता है। यह यह जानने में भी मदद करता है कि हुड के नीचे क्या हो रहा है ताकि आप किसी भी संभावित समस्याओं को दूर कर सकें।

मिशन क्रिटिकल सिस्टम के लिए विश्वसनीय कोड लिखना आसान नहीं है, आप जिस भी भाषा में हैं। लेकिन मैं सकारात्मक हूं। .NET को सही ढंग से करना असंभव नहीं है। इसके अलावा AFAIK, .NET थ्रेडिंग C / C ++ में थ्रेडिंग से अलग नहीं है, यह कुछ .net विशिष्ट कंस्ट्रक्शंस (जैसे RWL और इवेंट क्लासेस के लाइट वेट वर्जन जैसे) को छोड़कर एक ही सिस्टम कॉल का उपयोग करता है (या इससे बनाया गया है)।

पहली बार मैंने शब्द झगड़े के बारे में सुना है, लेकिन आपके विवरण के आधार पर, आपके सहकर्मी का मतलब संभवतः एक धागा था जो सभी संसाधनों को जारी किए बिना समाप्त हो गया। यह संभावित रूप से गतिरोध, स्मृति रिसाव या कुछ अन्य बुरे दुष्प्रभावों का कारण बन सकता है। यह स्पष्ट रूप से वांछनीय नहीं है, लेकिन .NET की एकलिंग इस कारण से हो सकती है क्योंकि संभवतः यह एक अच्छा विचार नहीं है क्योंकि यह अन्य भाषाओं में भी संभव है। मैं यह भी तर्क दूंगा कि .NET / की तुलना में C / C ++ में गड़बड़ करना आसान है (विशेष रूप से C में जहां आपके पास RAII नहीं है) लेकिन बहुत सारे महत्वपूर्ण एप्लिकेशन C / C ++ में लिखे गए हैं? तो यह वास्तव में आपकी व्यक्तिगत परिस्थितियों पर निर्भर करता है। यदि आप अपने अनुप्रयोग से गति के प्रत्येक औंस को निकालना चाहते हैं और यथासंभव नंगे धातु के करीब जाना चाहते हैं, तो .NET हो सकता हैसबसे अच्छा समाधान नहीं है। यदि आप एक तंग बजट पर हैं और वेब सेवाओं / मौजूदा .net पुस्तकालयों / आदि के साथ बहुत अधिक अंतर करते हैं तो .NET एक अच्छा विकल्प हो सकता है।


(1) मुझे यकीन नहीं है कि जब मैं डेड एंड externमेथड मारता हूं तो हूड के नीचे क्या होता है, इसका पता कैसे लगाया जाए । यदि आपको कोई सुझाव मिला है, तो मुझे यह सुनना अच्छा लगेगा। (2) मैं सहमत हूँ कि यह .NET में करना संभव है। मुझे विश्वास है कि यह लॉकिंग के साथ संभव है, लेकिन मुझे अभी तक इसका औचित्य साबित करने के लिए एक संतोषजनक जवाब नहीं मिला है
smartcaveman

1
@smartcaveman यदि आप जो चाहते हैं lockingवह lockकीवर्ड है, तो शायद तब से नहीं जब तक कि यह निष्पादन को क्रमबद्ध न कर दे। थ्रूपुट को अधिकतम करने के लिए, आपको अपने कोड की विशेषताओं के आधार पर सही निर्माण का उपयोग करना होगा। मैं कहूँगा कि यदि आप c / c ++ / java / जो भी pthreads / boost / thread pools / जो कुछ भी हो का उपयोग करके विश्वसनीय कोड लिख सकते हैं, तो आप इसे C # में भी लिख सकते हैं। लेकिन अगर आप किसी भी लाइब्रेरी का उपयोग करके किसी भी भाषा में विश्वसनीय कोड नहीं लिख सकते हैं, तो मुझे संदेह है कि C # में लिखना किसी भी अलग होगा।
जेरहमेल

@smartcaveman के रूप में पता लगाने के लिए क्या हुड के नीचे है, Google हीप्स की मदद करता है और यदि आप जारी कर रहे हैं तो वेब पर खोजने के लिए बहुत अधिक विदेशी है, रिफ्लेक्टर बहुत आसान है। लेकिन थ्रेडिंग क्लासेस के लिए, मुझे MSDN प्रलेखन बहुत उपयोगी लगता है। और इसके बहुत सारे रैपर उसी सिस्टम कॉल के लिए रैपर हैं जिसका उपयोग आप Cway में करते हैं।
जेरहमील

1
@smartcaveman बिल्कुल नहीं, मेरा मतलब यह नहीं है। मुझे खेद है अगर यह इस तरह से आया। मैं जो कहना चाहता था वह यह है कि आपको एक महत्वपूर्ण एप्लिकेशन लिखते समय .NET लिखने की जल्दी नहीं होनी चाहिए। ज़रूर, आप सामान कर सकते हैं कि शायद ज़ोंबी थ्रेड्स (जो मुझे लगता है कि केवल थ्रेड्स हैं जो किसी भी मानव रहित संसाधनों को जारी नहीं करते हैं, जो पूरी तरह से अन्य भाषाओं में हो सकते हैं: stackoverflow.com/questions/14268080/… ), लेकिन फिर, इसका मतलब यह नहीं है कि .NET एक व्यवहार्य समाधान नहीं है।
यरहमेल

2
मुझे नहीं लगता कि .NET एक बुरी तकनीक है। यह वास्तव में मेरा प्राथमिक विकास ढांचा है। लेकिन, इस वजह से, मुझे लगता है कि यह महत्वपूर्ण है कि मैं उन दोषों को समझता हूं जिनके लिए यह अतिसंवेदनशील है। मूल रूप से, मैं .NET बाहर गा रहा हूं, लेकिन क्योंकि मुझे यह पसंद है, इसलिए नहीं कि मैं नहीं करता हूं। (और कोई चिंता नहीं भाई, मैं + 1-ed आप)
smartcaveman

26

अभी मेरा अधिकांश जवाब नीचे दी गई टिप्पणियों द्वारा सही किया गया है। मैं उत्तर नहीं हटाऊंगा क्योंकि मुझे प्रतिष्ठा बिंदुओं की आवश्यकता है क्योंकि टिप्पणियों में जानकारी पाठकों के लिए मूल्यवान हो सकती है।

अमर ब्लू ने बताया कि .NET 2.0 और अप finallyब्लॉक थ्रेड गर्भपात के लिए प्रतिरक्षा हैं। और जैसा कि एंड्रियास निडरमेयर ने टिप्पणी की थी, यह एक वास्तविक ज़ोंबी धागा नहीं हो सकता है, लेकिन निम्नलिखित उदाहरण से पता चलता है कि कैसे एक धागे को नष्ट करने से समस्याएं हो सकती हैं:

class Program
{
    static readonly object _lock = new object();

    static void Main(string[] args)
    {
        Thread thread = new Thread(new ThreadStart(Zombie));
        thread.Start();
        Thread.Sleep(500);
        thread.Abort();

        Monitor.Enter(_lock);
        Console.WriteLine("Main entered");
        Console.ReadKey();
    }

    static void Zombie()
    {
        Monitor.Enter(_lock);
        Console.WriteLine("Zombie entered");
        Thread.Sleep(1000);
        Monitor.Exit(_lock);
        Console.WriteLine("Zombie exited");
    }
}

हालांकि जब एक lock() { }ब्लॉक का उपयोग किया जाता है, finallyतब भी निष्पादित किया जाएगा जब ThreadAbortExceptionउस तरह से निकाल दिया जाता है।

निम्न जानकारी, जैसा कि यह पता चला है, केवल .NET 1 और .NET 1.1 के लिए मान्य है:

यदि lock() { }ब्लॉक के अंदर एक अन्य अपवाद होता है, और ThreadAbortExceptionठीक उसी समय आता है जब finallyब्लॉक चलने वाला होता है, तो लॉक जारी नहीं किया जाता है। जैसा कि आपने उल्लेख किया है, lock() { }ब्लॉक इस प्रकार संकलित है:

finally 
{
    if (lockWasTaken) 
        Monitor.Exit(temp); 
}

यदि दूसरा थ्रेड Thread.Abort()उत्पन्न finallyब्लॉक के अंदर कॉल करता है, तो लॉक जारी नहीं किया जा सकता है।


2
आप बात कर रहे हैं, lock()लेकिन मैं इसका कोई उपयोग नहीं देख सकता ... तो - यह कैसे जुड़ा है? इस का एक "गलत" उपयोग है Monitor.Enterऔर Monitor.Exit(के उपयोग की कमी tryऔर finally)
एंड्रियास Niedermair

4
मैं यह नहीं कहूंगा कि एक ज़ोंबी-धागा - यह केवल एक गलत उपयोग है Monitor.Enterऔर Monitor.Exitबिना उचित उपयोग के tryऔर finally- वैसे भी, आपका परिदृश्य अन्य थ्रेड्स को लॉक करेगा, जो कि लटका सकता है _lock, इसलिए एक डेडलॉक-परिदृश्य है - जरूरी नहीं कि एक ज़ोंबी थ्रेड ... इसके अलावा, आप लॉक को रिलीज़ नहीं कर रहे हैं Main... लेकिन, हे ... शायद ओपी ज़ोंबी-थ्रेड्स के बजाय गतिरोध के लिए लॉक कर रहा है :)
एंड्रियास निडरमेयर

1
@AndreasNiedermair शायद एक ज़ोंबी धागे की परिभाषा काफी नहीं है जो मैंने सोचा था। शायद हम इसे "थ्रेड जिसे निष्पादन समाप्त कर दिया है, लेकिन सभी संसाधनों को जारी नहीं किया है" कह सकते हैं। मेरे होमवर्क को हटाने और करने के लिए प्रलोभन दिया गया, लेकिन ओपी के परिदृश्य के समान है।
C.Evenhuis

2
यहाँ कोई अपराध नहीं है! वास्तव में आपके उत्तर ने मुझे इसके बारे में सोचने के लिए मिला :) जैसा कि ओपी स्पष्ट रूप से तालों को जारी नहीं करने के बारे में बात कर रहा है, मेरा मानना ​​है कि उनके सह-साथी ने मृत-लॉकिंग के बारे में बात की - क्योंकि ताला कोई वास्तविक-संसाधन नहीं है जो एक धागे से बंधा हुआ है ( यह साझा किया गया है ... नोना) - और इसलिए किसी भी "ज़ॉम्बी" धागे को सर्वोत्तम-प्रथाओं से चिपकाकर lockया उचित try/ finally-उपयोग करके रोका जा सकता है
एंड्रियास

1
@ C.Evenhuis - मुझे यकीन नहीं है कि मेरी परिभाषा सटीक है। मैं सवाल क्यों पूछ रहा हूं इसका एक हिस्सा यह स्पष्ट करना है। मुझे लगता है कि अवधारणा को C / C ++
smartcaveman

24

यह ज़ोंबी थ्रेड्स के बारे में नहीं है, लेकिन किताब इफेक्टिव सी # में आईडीसिसोप्लिमेंट (आइटम 17) को लागू करने पर एक सेक्शन है, जो ज़ोंबी ऑब्जेक्ट्स के बारे में बात करता है जो मुझे लगा कि आपको दिलचस्प लग सकता है।

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

यह नीचे के समान एक उदाहरण देता है:

internal class Zombie
{
    private static readonly List<Zombie> _undead = new List<Zombie>();

    ~Zombie()
    {
        _undead.Add(this);
    }
}

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

एक अधिक पूर्ण उदाहरण नीचे है। जब तक फ़ॉरच लूप पहुँच जाता है, तब तक आपके पास चित्र वाली प्रत्येक अंडरड लिस्ट में 150 ऑब्जेक्ट होते हैं, लेकिन चित्र GC'd है और यदि आप इसका उपयोग करने का प्रयास करते हैं, तो आपको एक अपवाद मिलता है। इस उदाहरण में, मुझे एक ArgumentException मिल रही है (पैरामीटर मान्य नहीं है) जब मैं कोशिश करता हूं और छवि के साथ कुछ भी करता हूं, चाहे मैं इसे बचाने की कोशिश करूं, या यहां तक ​​कि ऊंचाई और चौड़ाई जैसे आयाम भी देख सकता हूं:

class Program
{
    static void Main(string[] args)
    {
        for (var i = 0; i < 150; i++)
        {
            CreateImage();
        }

        GC.Collect();

        //Something to do while the GC runs
        FindPrimeNumber(1000000);

        foreach (var zombie in Zombie.Undead)
        {
            //object is still accessable, image isn't
            zombie.Image.Save(@"C:\temp\x.png");
        }

        Console.ReadLine();
    }

    //Borrowed from here
    //http://stackoverflow.com/a/13001749/969613
    public static long FindPrimeNumber(int n)
    {
        int count = 0;
        long a = 2;
        while (count < n)
        {
            long b = 2;
            int prime = 1;// to check if found a prime
            while (b * b <= a)
            {
                if (a % b == 0)
                {
                    prime = 0;
                    break;
                }
                b++;
            }
            if (prime > 0)
                count++;
            a++;
        }
        return (--a);
    }

    private static void CreateImage()
    {
        var zombie = new Zombie(new Bitmap(@"C:\temp\a.png"));
        zombie.Image.Save(@"C:\temp\b.png");
    }
}

internal class Zombie
{
    public static readonly List<Zombie> Undead = new List<Zombie>();

    public Zombie(Image image)
    {
        Image = image;
    }

    public Image Image { get; private set; }

    ~Zombie()
    {
        Undead.Add(this);
    }
}

फिर से, मुझे पता है कि आप विशेष रूप से ज़ोंबी थ्रेड्स के बारे में पूछ रहे थे, लेकिन प्रश्न का शीर्षक .net में लाश के बारे में है, और मुझे इस बारे में याद दिलाया गया था और सोचा कि दूसरों को यह दिलचस्प लग सकता है!


1
यह दिलचस्प है। है_undead स्थिर होना?
स्मार्टक्वेमैन

1
तो मैंने इसे आजमाया, "नष्ट" वस्तु से कुछ छपाई के साथ। यह इसे एक सामान्य वस्तु की तरह मानता है। क्या ऐसा करने में कोई समस्या है?
स्मार्टकेवमैन

1
मैंने अपने उत्तर को एक उदाहरण के साथ अद्यतन किया है जो उम्मीद करता है कि इस मुद्दे को थोड़ा और स्पष्ट रूप से प्रदर्शित करता है।
JMK

1
मैं नहीं जानता कि आप क्यों अपमानित हुए। मुझे यह मददगार लगा। यहाँ एक सवाल है - आप किस तरह का अपवाद प्राप्त करने जा रहे हैं? मुझे उम्मीद नहीं है कि यह एक होगा NullReferenceException, क्योंकि मुझे लगता है कि लापता चीज़ को मशीन की तुलना में अधिक बंधे होने की आवश्यकता है। क्या यह सही है?
होशियार आदमी

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

21

भारी लोड के तहत महत्वपूर्ण प्रणालियों पर, प्रदर्शन सुधारों के कारण लॉक-फ्री कोड लिखना मुख्य रूप से बेहतर है। LMAX जैसे सामान को देखें और यह कैसे "यांत्रिक सहानुभूति" का लाभ उठाता है इसके बारे में महान चर्चा के लिए। ज़ोंबी धागे के बारे में चिंता हालांकि? मुझे लगता है कि यह एक किनारे का मामला है जो सिर्फ एक बग को इस्त्री करने के लिए है, और उपयोग नहीं करने के लिए एक अच्छा पर्याप्त कारण नहीं है lock

अपने दोस्त की तरह लग रहा है और सिर्फ कल्पना की जा रही है और मेरे लिए अस्पष्ट विदेशी शब्दावली के अपने ज्ञानपूर्ण झलके! हर समय जब मैं Microsoft UK में प्रदर्शन प्रयोगशालाएँ चला रहा था, मैं कभी भी .NET में इस मुद्दे के उदाहरण पर नहीं आया था।


2
मुझे लगता है कि अलग-अलग बग के बारे में अनुभवों के विभिन्न सेट हमें पागल बना देते हैं। उन्होंने इसे समझाते हुए एक चरम किनारे का मामला स्वीकार किया, लेकिन अगर यह वास्तव में एक किनारे का मामला है और कभी नहीं का मामला है, तो मैं कम से कम इसे थोड़ा बेहतर समझना
चाहूंगा

1
काफी उचित। मैं सिर्फ यह नहीं चाहूंगा कि आप lockबयान के बारे में चिंतित हों !
जेम्स वर्ल्ड

1
अगर मुझे इस मुद्दे की गहरी समझ होती तो मैं बहुत कम चिंतित होता।
स्मार्टवॉमन

4
मैंने अपवित्र किया क्योंकि आप कुछ धागे-एफयूडी से छुटकारा पाने की कोशिश कर रहे हैं, जिनमें से बहुत अधिक है। लॉक-एफयूडी :) को निपटाने के लिए और अधिक काम करने जा रहा है :) मैं बस उखड़ जाती हूं जब देवता एक अनबाउंड स्पिनलॉक लेते हैं, (प्रदर्शन के लिए), ताकि वे विस्तृत क्यू पर 50K डेटा कॉपी कर सकें।
मार्टिन जेम्स

3
हां, सामान्य और विशेष दोनों में। सही लॉक-फ्री कोड लिखना उतना ही चुनौतीपूर्ण है जितना प्रोग्रामिंग को प्राप्त करना। अधिकांश मामलों के लिए मेरे अनुभव में, lockब्लॉक करने के लिए आसान बड़े वसा वाले पाठ्यक्रम (दानेदार) अपेक्षाकृत ठीक हैं। आपको प्रदर्शन अनुकूलन की खातिर जटिलता को पेश करने से बचना चाहिए, जब तक कि आपको पता न हो कि आपको क्या करना है।
जेम्स वर्ल्ड

3

1. "स्पष्ट रूप से" ज़ोंबी थ्रेड की परिभाषा है जो मैंने यहां बताई है?

मैं सहमत हूं कि "ज़ोंबी थ्रेड्स" मौजूद हैं, यह एक ऐसा शब्द है जो थ्रेड्स के साथ होता है, जो संसाधनों से बचे हुए हैं और उन्हें पूरी तरह से मरने नहीं देते हैं, इसलिए इसका नाम "ज़ोंबी," है। इस रेफरल की व्याख्या पैसे पर बहुत सही है!

2. ज़ोंबी थ्रेड्स .NET पर होते हैं? (क्यों नहीं?)

हाँ वे हो सकते हैं। यह एक संदर्भ है, और वास्तव में विंडोज द्वारा "ज़ोंबी" के रूप में संदर्भित किया जाता है: MSDN मृत प्रक्रियाओं / थ्रेड्स के लिए शब्द "ज़ोंबी" का उपयोग करता है

बार-बार यह एक और कहानी है, और आपकी कोडिंग तकनीकों और प्रथाओं पर निर्भर करता है, जैसा कि आपके लिए है कि थ्रेड लॉकिंग की तरह है और इसे थोड़ी देर के लिए किया है, तो मुझे उस परिदृश्य के बारे में चिंता भी नहीं होगी।

और हाँ, जैसा कि @KevinPanko ने टिप्पणियों में सही ढंग से उल्लेख किया है, "ज़ोंबी थ्रेड्स" यूनिक्स से आते हैं, यही वजह है कि उन्हें XCode-ObjectiveC में उपयोग किया जाता है और "NSZombie" के रूप में संदर्भित किया जाता है और डीबगिंग के लिए उपयोग किया जाता है। यह उसी तरह से बहुत व्यवहार करता है ... एकमात्र अंतर एक ऐसी वस्तु है जो मर जाना चाहिए "ज़ोंबी थ्रेड" के बजाय "ज़ोंबी थ्रेड" के लिए "ज़ोंबीऑबजेक्ट" बन जाता है जो आपके कोड में एक संभावित समस्या हो सकती है।


1
लेकिन जिस तरह से एमएसडीएन ज़ोंबी का उपयोग करता है वह इस सवाल का उपयोग करने के तरीके से बहुत अलग है।
बेन Voigt

1
अरे हाँ मैं सहमत हूँ, लेकिन मैं एक मुद्दा बना रहा था कि यहां तक ​​कि MSDN को थ्रेड्स के रूप में संदर्भित किया जाता है जब मृत हो जाते हैं। और यह कि वे वास्तव में हो सकते हैं।
SH

4
ज़रूर, लेकिन यह कुछ अन्य कोड की बात कर रहा है, फिर भी धागे को संभाल रहा है, न कि जब यह बाहर निकलता है तो धागा होल्डिंग संसाधनों को संभालता है। प्रश्न में परिभाषा से सहमत आपका पहला वाक्य, क्या गलत है।
बेन वोइग्ट

1
आह मैं आपकी बात देख रहा हूं। सच कहूं तो मैंने भी ऐसा नहीं देखा। मैं उसकी बात पर ध्यान केंद्रित कर रहा था कि परिभाषा मौजूद है, चाहे वह कैसे भी हो। याद रखें कि धागे के साथ क्या होता है, इसकी परिभाषा मौजूद है, न कि यह कि यह कैसे किया जाता है।
SH

0

मैं ज़ोंबी धागे को आसानी से पर्याप्त बना सकता हूं।

var zombies = new List<Thread>();
while(true)
{
    var th = new Thread(()=>{});
    th.Start();
    zombies.Add(th);
}

यह थ्रेड हैंडल (के लिए) लीक करता है Join() ) । यह केवल एक और स्मृति रिसाव है जहाँ तक हम प्रबंधित दुनिया में चिंतित हैं।

अब फिर, एक धागे को इस तरह से मारना कि वह वास्तव में ताले रखता है, रियर में एक दर्द है लेकिन संभव है। दूसरे आदमी का ExitThread()काम करता है। जैसा कि उन्होंने पाया, फ़ाइल संभाल gc द्वारा साफ हो गया, लेकिन एक lockवस्तु के आसपास नहीं होगा। लेकिन आप ऐसा क्यों करेंगे?

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