1

TThread后代一起工作时,我基本上有一个选择:

  • 设置FreeOnTerminatetrue删除我的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,以便在下次调用启动/重新启动之前该对象不存在?这不能通过FreeOnTerminate设置为 true 来完成,因为它会删除对象。我只能尝试访问然后生成异常的对象(我可以捕获但它是愚蠢的)。在初始化或重新启动之前,我真的只需要知道 MyThread 是否已完成执行。

  • 我可以在不终止线程的情况下重新启动线程吗(在程序完成之前我真的不需要删除对象) - 如果我启动线程,我会得到“无法在正在运行或挂起的线程上调用启动”异常。

4

2 回答 2

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;
于 2013-04-04T20:22:13.770 回答
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;
}
于 2013-04-04T20:34:14.127 回答