Multithreading 终止线程变量并将其设置为NULL
使用Multithreading 终止线程变量并将其设置为NULL,multithreading,c++builder,tthread,Multithreading,C++builder,Tthread,使用TThread子代时,我基本上有一个选择: 将FreeOnTerminate设置为true,删除我的TThread子体对象,但不将其设置为NULL 手动操作,然后亲自完成移除的所有步骤 我基本上需要的是一种确定线程是否正在运行的方法,因此我执行了以下操作: //------------------------------------------------------------------------------ // Thread descendant //-------------
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);
}
}
//------------------------------------------------------------------------------
//线程后代
//------------------------------------------------------------------------------
类TMyThread:publictthread
{
private:UnicodeString StatusLine;//用于同步功能
void uu fastcall UpdateGUI();
受保护:虚拟void_uufastcall Execute();
public:_fastcall TMyThread();
};
//------------------------------------------------------------------------------
TMyThread*MyThread;
//------------------------------------------------------------------------------
//线程构造函数
__快速调用TMyThread::TMyThread():TThread(true)
{
FreeOnTerminate=false;
优先级=tpNormal;
}
//Form1的同步功能
void uu fastcall TMyThread::UpdateGUI()
{
Form1->Label1=状态行;
}
//执行代码
void uu fastcall TMyThread::Execute()
{
睡眠(2000年);
StatusLine=“我几乎完成了!”;
同步(&UpdateGUI);
}
//线程终止,删除对象,设置为NULL
void _fastcall TForm1::ThreadTerminateIfDone(TMyThread*T)
{
如果(T!=NULL&&WaitForSingleObject(重新解释强制转换(T->Handle),0)=WAIT\u OBJECT\u 0)
{
T->Terminate();
T->WaitFor();
删除T;
T=零;
}
}
//初始化部分,需要检查线程是否已经运行
void _fastcall TForm1::StartOrRestartThread(TObject*发送方)
{
//如果完成,请移除旧螺纹
螺纹端接FDONE(MyThread);
//检查线程是否正在运行-NULL=未运行且已终止或未初始化
if(MyThread==NULL)
{
MyThread=新的TMyThread();
MyThread->Start();
}
其他的
{
应用程序->消息框(L“线程仍在运行,请稍候!”,L“错误”,MB_OK);
}
}
此代码按原样工作。我的问题是:
- 有没有办法简化这一点?完成后,我需要将
设置为NULL,以便在下次调用start/restart之前对象不存在?如果将MyThread
设置为true,则无法执行此操作,因为它会删除对象。我只能尝试访问对象,然后该对象会生成异常(我可以捕获,但它是哑的)。在初始化或重新启动MyThread之前,我只需要知道MyThread是否已执行完毕FreeOnTerminate
- 我可以在不终止线程的情况下重新启动线程吗(在程序完成之前我不需要删除对象)-如果我启动线程,我会得到“无法在运行或挂起的线程上调用start”异常
- 在线程中运行while循环,并在顶部进行一些等待,以允许它在收到信号时运行一次,这比持续创建/终止/销毁线程以及相关的微管理更可取,因此没有其他过程是合理的
创建线程,将其放入一个while循环,在循环的顶部加上一个wait,发出信号让它运行,并且永远不要终止线程,除非绝对强制终止
死亡召唤:
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;
ThreadTerminateIfDone()
函数需要通过引用获取线程指针,否则将无法将指针正确设置为NULL:
void __fastcall TForm1::ThreadTerminateIfDone(TMyThread* &T)
话虽如此,如果使用线程的OnTerminate
事件跟踪线程是否正在运行,则可以完全消除ThreadTerminateIfDone()
。当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;
//------------------------------------------------------------------------------
要回答您的另一个问题,如果您希望线程可重启,则必须稍微更改线程设计,例如:
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;
//------------------------------------------------------------------------------
在没有同步的情况下,我应该如何更新VCL?线程是在“一次性”模式下完成的,所以一旦完成它就会自动终止,不需要循环。可以避免创建/删除,但一旦终止,我就无法重新启动它-我得到“无法启动挂起或终止的线程”。有什么想法吗?更新VCL:PostMessageAPI。线程是在“一次性”模式下完成的-停止“一次性”模式,并使用一个在顶部有同步对象等待的循环:事件或信号量。如果这样做,就不需要终止线程,因此也不需要尝试重新启动它——只需向synchro对象发送信号,while循环中的线程代码就会再次执行。只需让线程永远存在(即,直到应用程序终止,操作系统终止为止)。换句话说,你建议让线程使用100%的CPU运行一个空循环,并且只在发出工作信号时才执行操作?我可以将优先级降低到tpIdle,但仍然会使用100%的CPU。对CPU不是很友好。该线程需要连接到服务器,并可能每15分钟获取一次或两次数据。在空闲时间以循环方式运行它是没有意义的!等待内核同步对象-线程在其上阻塞,CPU使用率为0%,直到发出信号。在信号量上使用TEvent.WaitFor、TSimpleEvent.WaitFfor或WaitForSingleObject()。没有CPU密集型循环。好的,我们也会测试它。感谢您提出的好主意和付出的可见努力。我确实尝试过这一点,但您确定我可以在ThreadTerminated事件内部将MyThread设置为NULL吗?如果对象尚未释放,是否会导致访问冲突?@Coder12345:是的,我确定。
OnTerminate
事件通过Synchronize()
触发,线程对象将在OnTerminate
事件处理程序退出后才会释放。
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;
}