2017-04-02 8 views
5

फिलहाल मैं थ्रेड के बाद अच्छी तरह से मुक्त मेमोरी के लिए अतिरिक्त थ्रेड का उपयोग कर रहा हूं। पूछने से पहले। नहीं, मैं FreeOnTerminate का उपयोग नहीं कर सकता: = सत्य क्योंकि मुझे चाहिए। Waitfor। मुझे FreeAndNil() की भी आवश्यकता है क्योंकि केवल इस तरह से मैं जांच सकता हूं कि असाइन() का उपयोग करके थ्रेड चल रहा है या नहीं। उदाहरण कोड ,थ्रेड समाप्ति के बाद स्वचालित रूप से FreeAndNill() को निष्पादित करने के लिए कैसे करें

SupervisorThread := TSupervisorThread.Create(True); 
... 
SupervisorThread.OnTerminate := DoTerminateEvent; 
SupervisorThread.Resume; 

या धागे के निर्माता के लिए एक पैरामीटर के रूप में इसे पारित: जब धागा बनाने OnTerminate हैंडलर

private 
    procedure DoTerminateEvent(Sender: TObject); 

var 
    isRunning: Boolean; 

procedure TForm2.DoTerminateEvent(Sender: TObject); 
begin 
    isRunning := False; 
end; 

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 
    if (isRunning) then 
    begin 
    CanClose := false; 
    ShowMessage('Cannot close form because SupervisorThread is still working') 
    end else 
    CanClose := true; 
end; 

सेट करें:

procedure TForm1.Button1Click(Sender: TObject); 
begin 

    SupervisorThread:= TSupervisorThread.Create(True); 
    SupervisorThread.FreeOnTerminate:=false; //MUST BE FALSE! 
    SupervisorThread.Priority := tpNormal; 
    SupervisorThread.Resume; 

end; 

procedure TSupervisorThread.Execute; 
begin 

    CleaningThread:= TCleaningThread.Create(True); 
    CleaningThread.FreeOnTerminate:=true; 
    CleaningThread.Priority := tpNormal; 
    CleaningThread.Resume; 

    //some loops here 

end; 

procedure TCleaningThread.Execute; 
begin 

    if Assigned(SupervisorThread)=true then 
    begin 
    SupervisorThread.WaitFor; 
    FreeAndNil(SupervisorThread); 
    end; 

end; 

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 

    if Assigned(SupervisorThread)=false then CanClose:=true 
    else 
    begin 
    CanClose:=false; 
    ShowMessage('Cannot close form because SiupervisorThread is still working'); 
    end; 

end; 
+2

उपयोग घटनाओं, संकेत करने के लिए एर, घटनाओं –

+0

केवल एक चीज आप चाहते हैं धागा पूरा हुआ या नहीं पता करने के लिए है, तो एक 'OnTerminate' हैंडलर आवंटित धागे के लिए। –

+0

मुझे यह इंगित करना होगा कि एक थ्रेड जो 'पर्यवेक्षक थ्रेड.एटफ़ोर;' के साथ किसी अन्य थ्रेड द्वारा अवरुद्ध हो जाता है, थ्रेड के रूप में थोड़ा व्यर्थ लगता है। थ्रेड के बिंदु को याद रखें कोड को _concurrently_ निष्पादित करने की अनुमति देना है। आपका उदाहरण प्रश्न पूछता है: आप सुपरवाइजर के अंत में सफाई क्यों नहीं कर सकते? आपको सफाई वस्तु को सामने क्यों बनाना है; पर्यवेक्षक होने तक आप इंतजार नहीं कर सकते? यदि आप 'टर्मिनेट' सफाई करना चाहते हैं तो क्या होगा? - आप ऐसा नहीं कर सकते क्योंकि यह 'समाप्त नहीं होने पर' लूप में नहीं है। –

उत्तर

4

TThread.OnTerminate घटना का उपयोग करें

TSupervisorThread = class(TThread) 
public 
    constructor Create(OnTerminatEvent: TNotifyEvent); 
end; 

procedure TThreadCustom.Create(OnTerminateEvent: TNotifyEvent); 
begin 
    inherited Create(True); 
    OnTerminate := OnTerminateEvent; 
end; 

SupervisorThread := TSupervisorThread.Create(DoTerminateEvent); 
+0

मेरा डेल्फी कहता है "वास्तविक पैरामीटर नहीं" यहां पर्यवेक्षक थ्रेड.ऑनटर्मिनेट: = (DoTerminateEvent); –

+2

@Atak_Snajpera ऐसा इसलिए है क्योंकि प्रश्न में कोड गलत है। यदि आप प्रलेखन पढ़ेंगे, और इसके बारे में थोड़ा सोचेंगे, तो आप गलत काम करने में सक्षम होंगे। अपने लिए सोचने की कोशिश करना बंद मत करो। –

+0

मैंने ब्रैकेट के बिना पहले कोशिश की लेकिन मुझे "असंगत प्रकार: 'विधि सूचक और नियमित प्रक्रिया' –

1

आप जब एक धागा चलना समाप्त कर दिया पता लगाने के लिए, जैसे TThread.OnTerminate घटना का उपयोग कर सकते हैं:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if not Assigned(SupervisorThread) then 
    begin 
    SupervisorThread:= TSupervisorThread.Create(True); 
    SupervisorThread.FreeOnTerminate := False; 
    SupervisorThread.Priority := tpNormal; 
    SupervisorThread.OnTerminate := SupervisorThreadTerminated; 
    SupervisorThread.Resume; 
    end; 
end; 

procedure TForm1.SupervisorThreadTerminated(Sender: TObject); 
begin 
    SupervisorThread := nil; 
end; 

बहरहाल, यह कुछ समस्याओं का पैदा करता है। यह दौड़ की स्थिति बनाता है, क्योंकि सफाई धागा SupervisorThread पॉइंटर पर कार्य करता है, जो सफाई थ्रेड अभी भी चल रहा है, जबकि किसी भी समय गायब हो सकता है। और यह एक स्मृति रिसाव बनाता है, क्योंकि इसे अभी भी समाप्त होने के बाद SupervisorThread ऑब्जेक्ट को मुक्त करने की आवश्यकता है, लेकिन आप OnTerminate हैंडलर में सीधे ऐसा नहीं कर सकते हैं।

एक बेहतर समाधान SupervisorThread पॉइंटर पर भरोसा नहीं करेगा।

var 
    SupervisorTerminated: TEvent; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    SupervisorTerminated := TEvent.Create(nil, True, True, ''); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    if Assigned(SupervisorThread) then 
    begin 
    SupervisorThread.Terminate; 
    while SupervisorTerminated.WaitFor(1000) = wrTimeout do 
     CheckSynchronize; 
    end; 
    SupervisorTerminated.Free; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if not Assigned(SupervisorThread) then 
    begin 
    SupervisorThread := TSupervisorThread.Create(True); 
    SupervisorThread.FreeOnTerminate := True; 
    SupervisorThread.Priority := tpNormal; 
    SupervisorThread.OnTerminate := SupervisorThreadTerminated; 
    SupervisorTerminated.ResetEvent; 
    SupervisorThread.Resume; 
    end; 
end; 

procedure TForm1.SupervisorThreadTerminated(Sender: TObject); 
begin 
    SupervisorThread := nil; 
    SupervisorTerminated.SetEvent; 
end; 

procedure TCleaningThread.Execute; 
begin 
    SupervisorTerminated.WaitFor(INFINITE); 
end; 

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 
begin 
    CanClose := (SupervisorTerminated.WaitFor(0) = wrSignaled); 
    if not CanClose then 
    ShowMessage('Cannot close form because Supervisor Thread is still working'); 
end; 
संबंधित मुद्दे

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