终止线程变量并将其设置为NULL

时间:2013-04-04 20:14:23

标签: multithreading c++builder tthread

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”异常。

2 个答案:

答案 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;
}