TThread.WaitFor Bug..

// 26 Haziran 2009 // Delphi

Yakın bir zamanda TThread sınıfına yine işim düşmüştü. Yazacağım bir kod parçasında bir thread’in işinin bitmesini beklemem gerekiyordu. Kodumu bu şekilde geliştirirken Delphi’nin bir bug’una rastladım ve bu hatayı Delphi ürün müdürü Nick Hodges‘a ilettim. Sorunun bir sonraki Delphi sürümünde ortadan kalkacağına inanıyorum.

Kısaca sorunun ne olduğundan bahsettikten sonra, mail yazışmalarımızı ilgilenenler için paylaşacağım. Bildiğiniz gibi TThread sınıfının WaitFor metodu bir thread’in işinin bitmesini beklemek için tasarlanmıştır. Ve görevini layıkı ile yerine getirir. Ancak, eğer thread kendi constructor’ında işi bittikten sonra yok edilsin ayarına set edildi ise o zaman bu bug ile karşılaşacaksınız. Thread’inizin constructor ‘ında FreeOnTerminate := true gibi bir satır kod yazdı iseniz ve thread’inizin bitmesini WaitFor ile bekliyorsanız, thread’inizin bitmesine müteakip hata ile karşılaşacaksınız. Bunun nedeni, Thread sınıfının destructor’ında işletim sistemi tarafından ayrılmış olan thread handle’ının CloseHandle ile serbest bırakılmasına karşılık WaitFor metodu içinde bu handle’ın kullanılmaya çalışılmasıdır. Sizlere bu sorun düzeltilinceye kadarki tavsiyem WaitForSingleObject(myThread.Handle, INFINITE) kodu ile bekleme yapmanızdır.

Delphi ürün müdürü ile yazışmalarımız aşağıdaki gibidir:

FW: TThread.WaitFor Bug.!‏
From: Nick Hodges (Nick.Hodges@embarcadero.com)
Sent: Wed 6/24/09 6:13 PM
To: king_of_delphi@hotmail.com (king_of_delphi@hotmail.com)
Thanks for the report!

From: Jason Sprenger
Sent: Wednesday, June 24, 2009 11:04
To: Seppy Bloom; Nick Hodges; Jason Vokes
Cc: Thom Gerdes; Marty Thompson
Subject: RE: TThread.WaitFor Bug.!

I’ve reviewed the bug report and attached to it a test case from the original program fragments.

–Jason

From: Seppy Bloom
Sent: Monday, June 22, 2009 10:24 PM
To: Nick Hodges; Jason Vokes
Cc: Thom Gerdes; Marty Thompson; Jason Sprenger
Subject: RE: TThread.WaitFor Bug.!

Raid #270371, so we can all track it’s progress.

Seppy

From: Nick Hodges
Sent: Monday, June 22, 2009 10:52 AM
To: Seppy Bloom; Jason Vokes
Cc: Thom Gerdes; Marty Thompson; Jason Sprenger
Subject: RE: TThread.WaitFor Bug.!

Yes, here in this email. :-P

From: Seppy Bloom
Sent: Monday, June 22, 2009 10:02
To: Nick Hodges; Jason Vokes
Cc: Thom Gerdes; Marty Thompson; Jason Sprenger
Subject: RE: TThread.WaitFor Bug.!

Is it reported somewhere? :)

Seppy

From: Nick Hodges
Sent: Monday, June 22, 2009 9:43 AM
To: Jason Vokes
Cc: Seppy Bloom; Thom Gerdes; Marty Thompson
Subject: FW: TThread.WaitFor Bug.!

Is there a bug here, folks?

Nick

From: Excellent Delphi [mailto:king_of_delphi@hotmail.com]
Sent: Monday, June 22, 2009 05:27
To: nick.hodges@borland.com; Nick Hodges
Subject: TThread.WaitFor Bug.!

Hi Nick, sorry about this e-mail. I dont know where the new quality central is.

Pls check the TThread.WaitFor method.

TMyThread = class(TThread)
protected
procedure Execute; override;
public
constructor Create;
end;

….
….
procedure TMyThread.Execute;
var
iCounter : Integer;
sVal : String;
begin
inherited;

for iCounter := 0 to 1000000 do sVal := InttoStr(iCounter);
end;

constructor TMyThread.Create;
begin
inherited Create(true);
FreeOnTerminate := true; // it will be a problem when u use waitfor for waiting thread’s termination
end;

procedure TForm1.Button1Click(Sender : TObject);
var
mThread : TMyThread;
begin
mThread := TMyThread.Creat e;
mThread.Resume;
mThread.WaitFor; // when we use WaitForSingleObject(mThread.Handle, INFINITE) the problem never been seen,
// because GetExitCodeThread dont called.

Caption := TimeToStr(Time);
end;

In classes.pas ThreadProc method is following;

function ThreadProc(Thread: TThread): Integer;
var
FreeThread: Boolean;
begin
{$IFDEF LINUX}
if Thread.FSuspended then sem_wait(Thread.FCreateSuspendedSem);
{$ENDIF}
try
if not Thread.Terminated then
try
Thread.Execute;
except
Thread.FFatalException := AcquireExceptionObject;
end;
fina lly
FreeThread := Thread.FFreeOnTerminate;
Result := Thread.FReturnValue;
Thread.DoTerminate;
Thread.FFinished := True;
SignalSyncEvent;
if FreeThread then Thread.Free;
{$IFDEF MSWINDOWS}
EndThread(Result);
{$ENDIF}
{$IFDEF LINUX}
// Directly call pthread_exit since EndThread will detach the thread causing
// the pthread_join in TThread.WaitFor to fail. Also, make sure the EndThreadProc
// is called just like EndThread would do. EndThreadProc should not return
// and call pthread_exit itself.
if Assigned(EndThreadProc) then
EndThreadProc(Result);
pthread_exit(Pointer(Result));
{$ENDIF}
end;
end;

When the Thread.Free call, thread handle will be invalid by CloseHandle, but WaitFor method still waits this thread. At the end of WaitFor method, it will try to call CheckThreadError(GetExitCodeThread(H[0], Result));

But H[0] is now invalid at this point, so we will give an exception. If you write “if FreeThread then Thread.Free;” line after the EndThread(Result) line, problem will be avoid.

Note: Problem is the same Delphi 7..2009
Best Regards
Tuğrul HELVACI

“TThread.WaitFor Bug..” için 7 Yorum

  1. Veli BOZATLI diyor ki:

    Üstad bizi yine gurulandırdı!

    Kafama takılan birşey var:
    TMyThread.Execute içerisinde Inherited kullanmışsınız. TThread.Execute “abstract” bir method. Bu methodu tekrar TMyThread.Execute’da çağırmak hataya sebep olmaz mı ?

  2. Tuğrul HELVACI diyor ki:

    Onu ben kullanmadım, Delphi’de virtual bir metod override edildiğinde ve Ctrl+Shift+C tuş kombinasyonları ile implementasyonu oluşturulduğunda Delphi otomatikman koyuyor inherited ibaresini. Bu mekanizmanın abstract metodlarda nasıl çalıştığından tam emin değilim, derleyicinin kodunu bilmediğimiz için. Ancak büyük ihtimalle, ata sınıfın ilgili metodunun abstract tanımlanması durumunda çağırıldığı noktaya geri dönüyordur. Ata sınıfta virtual; abstract; biçiminde tanımlanmış olan bir metodun, çocuk nesnelerde ezilerek kullanılmasında bir sorun olmaz ama ata sınıfın ilgili metodu ezilmeden çağırılırsa o zaman hata alırız.

  3. bayrak diyor ki:

    paylaşımlarınız için teşekkürler

  4. aykut diyor ki:

    Selamlar,
    Ben CBuilder kullanıcısıyım ve
    “http://mapage.noos.fr/qnno/pages/delphi_en.htm” adresindeki THotLog komponentini kullanmaya çalışıyorum fakat debug ederken,
    ” if (HotLog)
    delete HotLog;” satırından sonra ” EInvalidPointer with message (invalid pointer operation” mesajı veriyor. Sizin dediğiniz şeyleri yapmaya çalıstım ve tüm waitForlu satırları WaitForSingleObject(…) ile değiştirdim. Fakat sorun hala devam etmekte. Release modda exe yi tıklayıp sonra kapattıgımda boyle bir sorun belirmiyor. Bunun nedeni ne olabilir. Sizden rica etsem bu konuda bana yardımcı olurmusunuz? Bu komponentle ilgili satırları disable ettiğimde ve kodu oyle derlediğimde debug modda, formu kapatırken herhangi bir hata almamaktaym. Sorun ne olabilir?
    Saygılarımla

  5. Tuğrul HELVACI diyor ki:

    Merhaba Aykut bey, bana kalırsa ilgili sınıfın destructor’unu incelemelisiniz.

  6. Ahmet YEŞİLÇİMEN diyor ki:

    Sayın hocam sorunu;

    destructor TMyThread.destroy;
    begin
    inherited; //inherited kodu kaldırılarak atasınıftaki kodların //çalışmasını engellenebilir inherited anahtarı kaldırıldığında
    //sorun ortadan kalkacaktır

    end;

    Saygılarla
    Ahmet YEŞİLÇİMEN

  7. Ahmet YEŞİLÇİMEN diyor ki:

    Sayın hocam çözüm olarak sorunu şu şekilde çözebiliriz.

    destructor TMyThread.destroy;
    begin
    inherited; //inherited kodu kaldırılarak atasınıftaki kodların çalışmasını engellenebilir inherited //anahtarı kaldırıldığında
    sorun ortadan kalkacaktır arkadaşlar.

    end;

    Saygılarla
    Ahmet YEŞİLÇİMEN

aykut için yorum yazın