2012-05-01 11 views
7

मेरे पास एक डेल्फी एप्लिकेशन है जो कुछ TTimer.OnTimer ईवेंट पर 6 अज्ञात धागे उत्पन्न करता है।आवेदन पर डेल्फी में अज्ञात धागे को कैसे समाप्त करें?

यदि मैं टाइटलबार में एक्स बटन से एप्लिकेशन को बंद करता हूं तो पता $ C0000005 पर एक्सेस उल्लंघन का उपयोग किया जाता है और फास्टएमएम रिपोर्टों ने TAnonymousThread ऑब्जेक्ट्स को लीक किया है।

TThread.CreateAnonymousThread() विधि के साथ OnTimer ईवेंट में बनाए गए डेल्फी में अज्ञात धागे को मुक्त करने का सबसे अच्छा तरीका कौन सा है?

समाधान जो मेरे लिए काम किया:

गुमनाम सूत्र है जो उन्हें किया जा रहा नि: शुल्क एड पर समाप्त हो जाता है की एक आवरण बनाया गया।

type 
    TAnonumousThreadPool = class sealed(TObject) 
    strict private 
    FThreadList: TThreadList; 
    procedure TerminateRunningThreads; 
    procedure AnonumousThreadTerminate(Sender: TObject); 
    public 
    destructor Destroy; override; final; 
    procedure Start(const Procs: array of TProc); 
    end; 

{ TAnonumousThreadPool } 

procedure TAnonumousThreadPool.Start(const Procs: array of TProc); 
var 
    T: TThread; 
    n: Integer; 
begin 
    TerminateRunningThreads; 

    FThreadList := TThreadList.Create; 
    FThreadList.Duplicates := TDuplicates.dupError; 

    for n := Low(Procs) to High(Procs) do 
    begin 
    T := TThread.CreateAnonymousThread(Procs[n]); 
    TThread.NameThreadForDebugging(AnsiString('Test thread N:' + IntToStr(n) + ' TID:'), T.ThreadID); 
    T.OnTerminate := AnonumousThreadTerminate; 
    T.FreeOnTerminate := true; 
    FThreadList.LockList; 
    try 
     FThreadList.Add(T); 
    finally 
     FThreadList.UnlockList; 
    end; 
    T.Start; 
    end; 
end; 

procedure TAnonumousThreadPool.AnonumousThreadTerminate(Sender: TObject); 
begin 
    FThreadList.LockList; 
    try 
    FThreadList.Remove((Sender as TThread)); 
    finally 
    FThreadList.UnlockList; 
    end; 
end; 

procedure TAnonumousThreadPool.TerminateRunningThreads; 
var 
    L: TList; 
    T: TThread; 
begin 
    if not Assigned(FThreadList) then 
    Exit; 
    L := FThreadList.LockList; 
    try 
    while L.Count > 0 do 
    begin 
     T := TThread(L[0]); 
     T.OnTerminate := nil; 
     L.Remove(L[0]); 
     T.FreeOnTerminate := False; 
     T.Terminate; 
     T.Free; 
    end; 
    finally 
    FThreadList.UnlockList; 
    end; 
    FThreadList.Free; 
end; 

destructor TAnonumousThreadPool.Destroy; 
begin 
    TerminateRunningThreads; 
    inherited; 
end; 

अंत यहाँ आप इसे कैसे फोन कर सकते हैं:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    FAnonymousThreadPool.Start([ // array of procedures to execute 
    procedure{anonymous1}() 
    var 
     Http: THttpClient; 
    begin 
     Http := THttpClient.Create; 
     try 
     Http.CancelledCallback := function: Boolean 
      begin 
      Result := TThread.CurrentThread.CheckTerminated; 
      end; 
     Http.GetFile('http://mtgstudio.com/Screenshots/shot1.png', 'c:\1.jpg'); 
     finally 
     Http.Free; 
     end; 
    end, 

    procedure{anonymous2}() 
    var 
     Http: THttpClient; 
    begin 
     Http := THttpClient.Create; 
     try 
     Http.CancelledCallback := function: Boolean 
      begin 
      Result := TThread.CurrentThread.CheckTerminated; 
      end; 
     Http.GetFile('http://mtgstudio.com/Screenshots/shot2.png', 'c:\2.jpg'); 
     finally 
     Http.Free; 
     end; 
    end 
    ]); 
end; 

कोई स्मृति लीक, उचित शटडाउन और प्रयोग करने में आसान।

+1

'अज्ञात धागे' - ओह महान .. अब एम्बरकाडेरो ने हमें किस पर फंसाया है? –

+1

@ मार्टिन: कुछ भी डरावना नहीं, वास्तव में। यह एक धागा है जिसका निर्माण किसी अज्ञात विधि द्वारा निर्माण समय पर प्रदान किया जाता है। यह धागे को परिभाषित करते समय बंद करने का उपयोग करने देता है। –

+0

यह लगातार धागे को बना/नष्ट कर देता है, कुछ ऐसा जो मैंने पिछले 20 वर्षों में डेवलपर्स से बचने के लिए कहा है। फिर भी, अगर वास्तव में शुरू नहीं हुआ है, तो मैं नहीं देख सकता कि एवी क्यों होना चाहिए। –

उत्तर

14

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

CreateAnonymousThread पर कॉल FreeOnTerminate पर True पर एक थ्रेड बनाता है।

The thread is also marked as FreeOnTerminate, so you should not touch the returned instance after calling Start.

और इसलिए, लेकिन डिफ़ॉल्ट, आप थ्रेड के जीवनकाल पर नियंत्रण डालने की स्थिति में नहीं हैं। हालांकि, आप Start पर कॉल करने से पहले FreeOnTerminateFalse पर सेट कर सकते हैं। इस तरह:

MyThread := TThread.CreateAnonymousThread(MyProc); 
MyThread.FreeOnTerminate := False; 
MyThread.Start; 

हालांकि, मुझे यकीन नहीं है कि मैं ऐसा करूँगा। CreateAnonymousThread का डिज़ाइन यह है कि धागा स्वचालित रूप से समाप्ति पर मुक्त हो जाता है। मुझे लगता है कि मैं व्यक्तिगत रूप से या तो इच्छित डिजाइन का पालन करता हूं, या अपना खुद का TThread वंशज प्राप्त करता हूं।

+0

मैं देखता हूं। लेकिन मुझे अभी भी यह नहीं मिला है। TAnonymousThread TThread का वंशज है। इसलिए मैं उनकी एक सूची बनाए रख सकता हूं और उन्हें समाप्त करने का प्रयास कर सकता हूं (क्योंकि आरटीएल स्वचालित रूप से ऐसा नहीं करता है)। जब मैं इसे समाप्त करने का प्रयास करता हूं तो कहता है: प्रोजेक्ट mtgstudio.exe ने संदेश के साथ अपवाद वर्ग ईथ्रेड बढ़ाया 'थ्रेड त्रुटि: हैंडल अमान्य है (6)'। –

+0

अनाम थ्रेड के लिए दस्तावेज़ पढ़ें। आपको TThread का संदर्भ रखने की अनुमति नहीं है क्योंकि यह FreeOnTerminate का उपयोग करता है। –

+0

क्षमा करें, मैं इस परियोजना को नहीं देख सकता। मुझे लगता है कि मैंने आपके द्वारा पूछे गए प्रश्न का उत्तर दिया। अनिवार्य रूप से, आप एक अज्ञात धागा शुरू करते हैं जिसे आप उस पर नियंत्रण खो देते हैं। अब आप इसका संदर्भ नहीं दे सकते। –

3

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

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

+0

आप आसानी से एक TThread वंशज को अज्ञात विधि पास कर सकते हैं और निष्पादन विधि में निष्पादित कर सकते हैं। –

+0

बेशक, @ डेविड। उस का 'CreateAnonymousThread' प्रमाण नहीं है? तो क्या? –

+1

मेरा मतलब है कि यह आपके उत्तर की अंतिम वाक्य में सुझाए गए दृष्टिकोण का एक विकल्प होगा। –

8

CreateAnonymousThread का उपयोग कर त्रुटियों से बचने के लिए बस इसे शुरू करने से पहले FreeOnTerminateFalse पर सेट करें।

इस तरह आप थ्रेड के साथ काम कर सकते हैं जैसा कि आप आमतौर पर बिना किसी कामकाज के करते हैं।

आप प्रलेखन कि का कहना है कि CreateAnonymousThread स्वतः निर्धारित True करने के लिए FreeOnTerminate पढ़ सकते हैं और यह है कि क्या त्रुटियों खड़ी कर रहा है जब आप धागा संदर्भ है।

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