2009-07-06 14 views
15

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

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

while Suspended do 
    Resume; 

धागा बनाया गया था तो निलंबित कर दिया है, हम में चिंता करने की है कि जब हम धागा केवल इसे समाप्त करने के लिए फिर से शुरू TThread.Execute() विधि बुलाया जाएगा की जरूरत नहीं है - यह (कृपया मुझे सही नहीं होगा अगर मैं गलत हूँ)।

मैं क्या कहा गया है प्रत्येक TThread वस्तु के लिए कोड की निम्न लाइनों का उपयोग कर मुक्त कर दिया जा रहा है पता चलता है:

MyThread.Terminate; 
while MyThread.Suspended do 
    MyThread.Resume; 
MyThread.WaitFor; 
MyThread.Free; 

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

इसलिए मैं इस निष्कर्ष पर पहुंचा कि इन सभी को टीटीएचड क्लास के ओवरडिन विनाशक के अंदर रखा जा सकता है, जिसके लिए यह MyThread को कॉल करने के लिए पर्याप्त होगा। फ्री (या MyThread। अगर माई थ्रेड। फ्रीऑनटर्मिनेट सेट है तो देखभाल करें) इस बारे में कि नष्ट वस्तु एक टीटीएचड ऑब्जेक्ट है या नहीं:

destructor TMyThread.Destroy; 
begin 
    //if FreeOnTerminate, the calling thread cannot wait for itself 
    if GetCurrentThreadId <> ThreadId then 
    begin 
    Terminate; 
    while Suspended do 
     Resume; 
    WaitFor; 
    end; 

    {free all objects created in this class} 

    inherited Destroy; 
end; 

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

आपके सुझावों के लिए अग्रिम धन्यवाद।

+0

हेमलेट के लॉर्ड पोलोनियस के शब्दों से एक अनुस्मारक: ब्रेवटी बुद्धि की आत्मा है – Argalatyr

उत्तर

8

टीटीएचड में आपके सुझाव का पहले से ही प्रदर्शन किया गया है। डिस्ट्रॉय विनाशक, और TMyThread.free का आविष्कार करना आपके सुझावों को ही करेगा। थ्रेड क्लास के स्वामित्व वाली किसी भी ऑब्जेक्ट को साफ़ करने के लिए, आप ऑनटर्मिनेट ईवेंट में इसे निष्पादित कर सकते हैं, जिसे थ्रेड शट डाउन लॉजिक के हिस्से के रूप में बुलाया जाएगा।

+0

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

+4

@Mariusz: Suspend() और फिर से शुरू करें() के बिना कोड करने का प्रयास करें, और आपको वह समस्या नहीं होगी। ये विधियां बहुत ही समस्याग्रस्त हो सकती हैं, जैसा कि आपने स्वयं पाया है, और उनके बिना कोड करने का हमेशा एक तरीका है। थ्रेड को इसके बजाय एक या कई सिस्टम-प्रदान सिंक्रनाइज़ेशन प्राइमेटिव पर रोक दें। या संदेश लूप का उपयोग करें, [डेल्फी] में SO पर मल्टीथ्रेडिंग पर जानकारी के साथ कई जवाब हैं। – mghie

7

धागे को रोकने का कोई सार्वभौमिक तरीका नहीं है, क्योंकि प्रक्रिया को रोकने के लिए कोई सार्वभौमिक तरीका नहीं है। प्रत्येक एक अलग है।

कुछ धागे के लिए, Terminate विधि के माध्यम से Terminated संपत्ति सेट करने के लिए पर्याप्त है। अन्य धागे, हालांकि, GetMessage या MsgWaitForMultipleObjects जैसे कार्यों को कॉल करें, जो कुछ होने तक अवरुद्ध हो जाएंगे, जैसे कोई संदेश आने या कर्नेल हैंडल सिग्नल हो रहा है। TThread.Terminate उन चीजों में से कोई भी नहीं कर सकता है, इसलिए यह उन धागे को चलाना बंद नहीं कर सकता है। जब मैंने उन जैसे धागे लिखे हैं, तो मैंने उन्हें रोकने के लिए उन्हें सूचित करने के लिए अपने स्वयं के कार्य प्रदान किए हैं।मैं थ्रेड की कतार पर एक संदेश को मजबूर करने के लिए PostThreadMessage पर कॉल कर सकता हूं, या मैं उस घटना को सिग्नल कर सकता हूं जिसे थ्रेड क्लास ने समाप्त करने के अनुरोध को सूचित करने के लिए प्रदान किया है।

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

TThread.Terminate वर्चुअल थे तो यह बहुत अच्छा होगा। फिर प्रत्येक धागा वर्ग स्वयं को सूचित करने का एक कस्टम तरीका प्रदान कर सकता है कि इसे चलना बंद कर देना चाहिए। कुछ सिर्फ Terminated सेट कर सकते हैं, और अन्य स्वयं संदेश पोस्ट कर सकते हैं, घटनाओं को सिग्नल कर सकते हैं, या जो कुछ भी उन्हें चाहिए, कर सकते हैं। जैसा कि यह है, हालांकि, गैर-वर्चुअल विधि थ्रेड के साथ अच्छी तरह से काम नहीं करती है जो अन्य चीजों के लिए अपना बहुत समय व्यतीत करती है। वर्तमान तरीका केवल उन धागे के लिए काम करता है जो मतदान उनके Terminated गुणों में अक्सर सक्षम होते हैं।

कुछ धागे में उनके FreeOnTerminate गुण सेट हैं। उन धागे के लिए, आपका कोड सुरक्षित नहीं है। तकनीकी रूप से, किसी भी ऐसी वस्तुओं पर विधियों को कॉल करना सुरक्षित नहीं है क्योंकि थ्रेड किसी भी समय समाप्त हो सकता है। लेकिन अगर आपको पता है कि थ्रेड अभी भी चल रहा है और थ्रेड ऑब्जेक्ट अभी भी मौजूद है, तो ऑब्जेक्ट निश्चित रूप से Terminate पर कॉल के बाद कुछ समय के लिए मौजूदा बंद हो जाएगा। आप WaitFor पर एक फ्री-ऑन-टर्मिनेट थ्रेड ऑब्जेक्ट पर कॉल नहीं कर सकते हैं, और आप निश्चित रूप से Free पर कॉल नहीं कर सकते हैं।

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