zaplanowałem sobie, że za każdym razem gdy użytkownik naciśnie button`a będzie wykonywana metoda Execute (oczywiście za pomocą Resume), niestety wątek zostaje odpalony tylko za pierwszym razem, potem już metoda Resume nie uruchamia Execute. Da się zrobić taki obiekt-wątek wielokrotnego użytku czy może trzeba za...
Poniżej:
Rolę fun Execute spełnia dowolna fun void __fastcall Form1::fun(TObject *Sender)
Można ją uruchamiać wielokrotnie .Form1 + 5xButton + podpiąć odpowiednie ButtonClick .
Wątków nie można zabijać poprzez API w uruchomionym programie,bo to całkowicie
dezorganizuje jego działanie.
Wątek powinien zakończyć się "legalnie" .
Jeśli istnieją co do tego wątpliwości to można sprawdzać stan wątku
i zabezpieczyć się przed próbą usunięcia działającego obiektu
lub zastosować obsługę wyjątków ,pośmiertnie...
Unit1.h
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//*****************************************************************
class TThreadComponent ;
class TMyThread :public TThread{
TThreadComponent* tc ;
public:
void __fastcall Synchro(TThreadMethod &Method);
__fastcall TMyThread(bool CreateSuspended,
TThreadComponent* tthc);
__fastcall ~TMyThread();
void __fastcall Execute(void);
};
//*****************************************************************
const int THREAD_READY = 0 ;
const int THREAD_WAIT = 1 ;
const int THREAD_RUN = 2;
//*****************************************************************
class TThreadComponent : public TComponent
{
private:
TMyThread* pMyThread ;
TNotifyEvent execute ;
bool bSuspend ;
bool bRun ;
protected:
public:
__fastcall TThreadComponent(TComponent* Owner);
__fastcall ~TThreadComponent();
void __fastcall Suspend(void);
void __fastcall Resume(void);
void __fastcall Execute(void);
void __fastcall Synchronize(TThreadMethod &Method);
void __fastcall CreateNewMyThread(void);
int __fastcall Status(void);
//__published:
__property TNotifyEvent OnExecute = {read=execute ,write=execute
,default = 0};
};
//*****************************************************************
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TButton *Button2;
TButton *Button3;
TButton *Button4;
TButton *Button5;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall Button3Click(TObject *Sender);
void __fastcall Button4Click(TObject *Sender);
void __fastcall Button5Click(TObject *Sender);
private: // User declarations
TThreadComponent*pThread ;
void __fastcall ThreadFunc(TObject *Sender);
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
//=============== TMyThread ==========================================
void __fastcall TMyThread::Synchro(TThreadMethod &Method)
{
Synchronize(Method);
}
//-----------------------------------------------------------------
__fastcall TMyThread::TMyThread(bool CreateSuspended,
TThreadComponent* tthc):TThread(CreateSuspended)
{
tc = tthc ;
}
//-----------------------------------------------------------------
__fastcall TMyThread::~TMyThread()
{
MessageBox(NULL,"MyThread - KONIEC Wątku","Destruktor",MB_OK);
}
//---------------------------------------------------------------------------
//---------------- posrednie wywolanie wlasciwosci 'execute' przez
//---------------- obiekt TMyThread zawarty w TThreadComponent
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute(void)
{
tc->Execute();
//<---- Wątek kończy się
tc->CreateNewMyThread(); // <--- podstawiamy nowy obiekt TThread w TThreadComponent
// poprzedni zostanie usunięty automatycznie
// po zakończeniu Execute
}
//--------------------------------------------------------------------
//=============== TThreadComponent ==========================================
//---------------------------------------------------------------------------
__fastcall TThreadComponent::TThreadComponent(TComponent* Owner)
: TComponent(Owner)
{
CreateNewMyThread();
}
//---------------------------------------------------------------------------
void __fastcall TThreadComponent::Execute(void)
{
bRun = true ;
MessageBox(NULL,"Ececute","Execute",MB_OK);
if(execute)
{
execute(this); // Tu jest wywolywana TForm1::ThreadFunc(TObject *Sender)
} // jako osobny wątek
bRun = false ;
}
//-----------------------------------------------------
void __fastcall TThreadComponent::Synchronize(TThreadMethod &Method)
{
pMyThread->Synchro(Method);
}
//-----------------------------------------------------------------
void __fastcall TThreadComponent::Suspend(void)
{
if(!bSuspend)
{
pMyThread->Suspend();
bSuspend = true ;
}
}
//-----------------------------------------------------------------
void __fastcall TThreadComponent::Resume(void)
{
if(bSuspend)
{
pMyThread->Resume() ;
bSuspend = false ;
}
}
//----------------------------------------------------------------
__fastcall TThreadComponent::~TThreadComponent()
{
MessageBox(NULL,"Destruktor","ThreadComponent",MB_OK);
if(Status()==THREAD_READY)
{
pMyThread ->FreeOnTerminate = false;
delete pMyThread ;
pMyThread = NULL ;
}else{
throw 0 ; // zakończenie przy dzialajacym wątku
}
}
//------------------------------------------------------------------
void __fastcall TThreadComponent::CreateNewMyThread(void)
{
pMyThread = new TMyThread(true,this);
pMyThread->FreeOnTerminate = true ;
bSuspend = true ;
bRun = false ;
}
//------------------------------------------------------------------
int __fastcall TThreadComponent::Status(void)
{
if((!bRun)&& bSuspend)
{
return THREAD_READY ;
}
if(bRun && bSuspend )
{
return THREAD_WAIT ;
}
return THREAD_RUN ;
}
//*****************************************
//=============== Form1 konstruktor ===========================================
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
// Nowy obiekt Watku
pThread = new TThreadComponent(0);
pThread -> OnExecute = Form1->ThreadFunc ;
// Captiony dla Guzikow
Button1->Caption = "Resume" ;
Button2->Caption = "Suspend";
Button3->Caption = "ID";
Button4->Caption = "Koniec" ;
Button5->Caption = "Delete" ;
}
//----------------------------------------------------------------------------
//+++++++++++++++ Funkcja wątku ++++++++++++++++++++++++++++++++++++++++++++++
int end ;
//--------
void __fastcall TForm1::ThreadFunc(TObject *Sender)
{
end = false ;
// MessageBox bez Synchronize !
// To nie jest w 100% prawidlowe .
MessageBox(NULL,"Nowy Wątek",String((int)GetCurrentThreadId()).c_str(),MB_OK);
while(!end)
{
Beep(0x444,100);
Sleep(200);
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//----------------------------------------------------------------------------
//------- Guzik Resume
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(pThread->Status()!=THREAD_READY)
{
ShowMessage("Wątek jest uruchomiony.");
}
pThread->Resume();
}
//---------------------------------------------------------------------------
//------- Guzik Suspend
void __fastcall TForm1::Button2Click(TObject *Sender)
{
pThread->Suspend();
}
//---------------------------------------------------------------------------
//------- Guzik ID - id wątku glownego
void __fastcall TForm1::Button3Click(TObject *Sender)
{
MessageBox(NULL,"Wątek Glowny",String((int)GetCurrentThreadId()).c_str(),MB_OK);
}
//---------------------------------------------------------------------------
//------- Guzik Koniec Watku
void __fastcall TForm1::Button4Click(TObject *Sender)
{
if(pThread->Status()==THREAD_WAIT)
{
ShowMessage("Wątek dziala i jest zawieszony , wykonaj 'RESUME'.");
}else{
end = true ;
}
}
//---------------------------------------------------------------------------
//------- Guzik delete
void __fastcall TForm1::Button5Click(TObject *Sender)
{
// Sprawdz czy można bezpiecznie usunac obiekt
if(pThread->Status()!=THREAD_READY) // czy wątek zakonczony
{ // i czeka nowy?
ShowMessage("Nie można wykonac delete, wątek nie zakonczyl się.");
}else{
delete pThread;
Button5->Enabled = false ; // blok delete
Button1->Enabled = false ; // blok Resume
Button2->Enabled = false ; // blok Suspend
}
}
//---------------------------------------------------------------------------
Ps. Ubicie :
Zastępując kod destruktora przez :
__fastcall TThreadComponent::~TThreadComponent()
{
MessageBox(NULL,"Destruktor","ThreadComponent",MB_OK);
pMyThread ->Suspend(); // <--------
pMyThread ->FreeOnTerminate = false;
delete pMyThread ;
pMyThread = NULL ;
}
Można "Ubić" wątek w czasie jego wykonywania się i pominąć
sprawdzenia .
Można też zabić wątek bez usuwania podstawowego obiektu ,
stary wątek jest usuwany - delete i w jego miejsce
podstawiany nowy , oczekujący na wykonanie np.:
void __fastcall TThreadComponent::Break(void)
{
// Ubicie wątku
pMyThread ->Suspend();
pMyThread ->FreeOnTerminate = false;
delete pMyThread ;
pMyThread = NULL ;
CreateNewMyThread();
// zastąpienie nowym w stanie zawieszenia
/* CreateNewMyThread() ==[ pMyThread = new MyThread(Zawieszony==true) ]*/
}
.....
pThread->Break() ; // wywalamy wątek i bierzemy następny
....
Usuwamy normalnie .
delete pThread;
Ten kod działa powodując zabicie wątku z poprawnym wykonaniem
destruktora TThread bez załamania aplikacji i użycia bezpośrednio funkcji API
,ale czy jest do końca bezpieczny w użyciu to wymaga jeszcze przetestowania .
Fun API zabijające wątki pozostawiają stos funkcji wątku aby
nie narobić bałaganu oraz nie niszczą obiektów C++ utworzonych
w niszczonym wątku .
Gdyby kogoś to interesowało
dalsze rozważania , komponent + kod oparty na powyższych fragmentach będą dostępne
(od 01.03.2008) pod adresem:
http://www.win32prog.republika.pl/winapp/tcthelp.html
w 1 wersji testowej dla samobójców i ryzykantów.. [green] .
a nie w miejscu w którym został przerwany?
Pewnie tak ale będzie to wymagało kosmicznych wygibasów...