与TThread
后代合作时,我基本上可以选择:
FreeOnTerminate
设置为true
,删除我的TThread
后代对象,但不将其设置为NULL
我基本上需要的是一种确定线程是否正在运行的方法,因此我执行了以下操作:
//------------------------------------------------------------------------------
// Thread descendant
//------------------------------------------------------------------------------
class TMyThread : public TThread
{
private: UnicodeString StatusLine; // Used for Synchronize function
void __fastcall UpdateGUI();
protected: virtual void __fastcall Execute();
public: __fastcall TMyThread();
};
//------------------------------------------------------------------------------
TMyThread *MyThread;
//------------------------------------------------------------------------------
// Thread constructor
__fastcall TMyThread::TMyThread() : TThread(true)
{
FreeOnTerminate = false;
Priority = tpNormal;
}
// Synchronize function for Form1
void __fastcall TMyThread::UpdateGUI()
{
Form1->Label1 = StatusLine;
}
// Execute code
void __fastcall TMyThread::Execute()
{
Sleep(2000);
StatusLine = "I am almost done!";
Synchronize(&UpdateGUI);
}
// Thread terminate, delete object, set to NULL
void __fastcall TForm1::ThreadTerminateIfDone(TMyThread *T)
{
if (T != NULL && WaitForSingleObject(reinterpret_cast<void*>(T->Handle),0) == WAIT_OBJECT_0)
{
T->Terminate();
T->WaitFor();
delete T;
T = NULL;
}
}
// And initialization part which needs to check if thread is already running
void __fastcall TForm1::StartOrRestartThread(TObject *Sender)
{
// Remove old thread if done
ThreadTerminateIfDone(MyThread);
// Check if thread is running - NULL = not running and terminated or uninitialized
if (MyThread == NULL)
{
MyThread = new TMyThread();
MyThread->Start();
}
else
{
Application->MessageBox(L"Thread is still running please wait!", L"Error", MB_OK);
}
}
此代码按原样运行。我的问题是:
有没有办法简化这个?完成后我需要将MyThread
设置为NULL,以便在下次调用start / restart之前对象不在?将FreeOnTerminate
设置为true无法执行此操作,因为它会删除对象。我只能尝试访问然后生成异常的对象(我可以捕获但它很愚蠢)。我真的只需要知道MyThread在初始化或重新启动之前是否完成了执行。
我可以重新启动线程而不终止它(我不需要在程序完成之前删除对象) - 如果我启动线程我得到“无法在运行或挂起的线程上调用start”异常。
答案 0 :(得分:1)
在线程中运行while循环,在顶部有一些等待以允许它在发出信号时运行一次,这比继续创建/终止/销毁线程以及相关的微管理更好,没有其他方法是清醒。
创建线程,在顶部等待放入while循环,发出信号使其运行并且永远不会终止线程,除非绝对强制执行。
死亡召唤:
TThread.WaitFor
TThread.Synchronize
TThread.Terminate
非常努力不要使用这些。
简单示例:
TmyThread=class(TThread);
private;
mySimpleEvent:TSimpleEvent;
public
constructor create;
procedure go;
end;
constructor TmyThread.create;
begin
inherited create(true);
mySimpleEvent:=TSimpleEvent.Create;
resume;
end;
procedure TmyThread.go;
begin
mySimpleEvent.SetEvent;
end;
procedure TmyThread.Execute;
begin
while mySimpleEvent.WaitFor(INFINITE) do
begin
mySimpleEvent.ResetEvent;
//code to do your stuff
end;
end;
答案 1 :(得分:1)
你的ThreadTerminateIfDone()
函数需要通过引用获取线程指针,否则它将无法正确地将指针设置为NULL:
void __fastcall TForm1::ThreadTerminateIfDone(TMyThread* &T)
如上所述,如果使用线程的ThreadTerminateIfDone()
事件来跟踪线程是否正在运行,则可以完全消除OnTerminate
。当FreeOnTerminate
设置为true时,在释放线程之前触发OnTerminate
,例如:
class TMyThread : public TThread
{
private:
String StatusLine; // Used for Synchronize function
void __fastcall UpdateGUI();
protected:
virtual void __fastcall Execute();
public:
__fastcall TMyThread();
};
//------------------------------------------------------------------------------
extern TMyThread *MyThread;
//------------------------------------------------------------------------------
TMyThread *MyThread = NULL;
__fastcall TMyThread::TMyThread()
: TThread(true)
{
FreeOnTerminate = true;
Priority = tpNormal;
}
void __fastcall TMyThread::UpdateGUI()
{
Form1->Label1 = StatusLine;
}
void __fastcall TMyThread::Execute()
{
Sleep(2000);
StatusLine = "I am almost done!";
Synchronize(&UpdateGUI);
}
void __fastcall TForm1::StartOrRestartThread(TObject *Sender)
{
if (MyThread == NULL)
{
MyThread = new TMyThread();
MyThread->OnTerminate = ThreadTerminated;
MyThread->Start();
}
else
{
Application->MessageBox(L"Thread is still running please wait!", L"Error", MB_OK);
}
}
void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
MyThread = NULL;
}
要回答您的其他问题,如果您希望线程可以重新启动,那么您必须稍微更改线程设计,例如:
class TMyThread : public TThread
{
private:
String StatusLine; // Used for Synchronize function
TEvent *RestartEvent;
void __fastcall UpdateGUI();
protected:
virtual void __fastcall Execute();
public:
bool Busy;
__fastcall TMyThread();
__fastcall ~TMyThread();
void __fastcall Restart();
};
//------------------------------------------------------------------------------
extern TMyThread *MyThread;
//------------------------------------------------------------------------------
TMyThread *MyThread = NULL;
__fastcall TMyThread::TMyThread()
: TThread(true)
{
FreeOnTerminate = true;
Priority = tpNormal;
RestartEvent = new TEvent(nil, true, true, "");
}
__fastcall TMyThread::~TMyThread()
{
delete RestartEvent;
}
void __fastcall TMyThread::UpdateGUI()
{
Form1->Label1 = StatusLine;
}
void __fastcall TMyThread::Execute()
{
while (!Terminated)
{
if (RestartEvent.WaitFor(1000) == wrSignaled)
{
if (Terminated) return;
RestartEvent.ResetEvent();
Busy = true;
StatusLine = "I am doing something!";
Synchronize(&UpdateGUI);
Sleep(2000);
StatusLine = "I am almost done!";
Synchronize(&UpdateGUI);
Busy = false;
}
}
}
void __fastcall TForm1::StartOrRestartThread(TObject *Sender)
{
if (MyThread == NULL)
{
MyThread = new TMyThread();
MyThread->OnTerminate = ThreadTerminated;
MyThread->Start();
}
else if (!MyThread->Busy)
{
MyThread->Restart();
}
else
{
Application->MessageBox(L"Thread is still running please wait!", L"Error", MB_OK);
}
}
void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
MyThread = NULL;
}