I wrote a DLL in C++Builder XE6 that uses a thread to do some background task.
Here's the (simplified) code in the DLL:
typedef void (__stdcall* ERRORCALLBACK)();
class TMyThread : public TThread
{
typedef TThread inherited;
private:
void __fastcall DoError ();
public:
inline __fastcall TMyThread () : inherited(true) {}
ERRORCALLBACK OnError;
};
void __fastcall TMyThread::Execute ()
{
AddLog("Thread started (ID: " + UIntToStr(ThreadID) + ")");
try
{
while (!Terminated)
{
if (true) // Some error condition
{
AddLog("Before Synchronize(DoError)");
if (OnError)
Synchronize(DoError);
AddLog("After Synchronize(DoError)");
}
}
}
__finally
{
AddLog("Thread stopped (ID: " + UIntToStr(ThreadID) + ")");
}
}
void __fastcall TMyThread::DoError ()
{
AddLog("DoError() begins");
try
{
OnError();
}
catch (...)
{
}
AddLog("DoError() ends");
}
TMyThread* Thread = NULL;
void __declspec(dllexport) __stdcall StartThread (ERRORCALLBACK ErrorProc)
{
if (!Thread)
{
Thread = new TMyThread();
Thread->OnError = ErrorProc;
Thread->Start();
}
}
void __declspec(dllexport) __stdcall StopThread ()
{
if (Thread)
{
AddLog("Stopping thread (ID: " + UIntToStr(Thread->ThreadID) + ")");
Thread->Terminate();
Thread->WaitFor();
delete Thread;
Thread = NULL;
}
}
The AddLog()
function writes a text string to a log file.
The DLL is used by a VCL application, written in C++Builder 1.
Here's the code in the VCL application:
typedef void (__stdcall* ERRORCALLBACK)();
extern "C"
{
void __declspec(dllimport) __stdcall StartThread (ERRORCALLBACK ErrorProc);
void __declspec(dllimport) __stdcall StopThread ();
}
void __stdcall ThreadError ()
{
Form1->Memo1->Lines->Add("An error occurred!");
}
void __fastcall TForm1::Button1Click (TObject *Sender)
{
StartThread(ThreadError);
}
void __fastcall TForm1::Button2Click (TObject *Sender)
{
StopThread();
}
I run the VCL application, click Button1 to start the thread, wait a couple of seconds and click Button2 to stop the thread. Afterwards, the log file contains:
18-05-2022 13:52:22.798: Thread started (ID: 2756)
18-05-2022 13:52:22.804: Before Synchronize(DoError)
18-05-2022 13:52:45.530: Stopping thread (ID: 2756)
18-05-2022 13:52:45.530: DoError() begins
18-05-2022 13:52:45.530: DoError() ends
18-05-2022 13:52:45.530: After Synchronize(DoError)
18-05-2022 13:52:45.530: Thread stopped (ID: 2756)
Apparently, the call to Synchronize()
hangs until the thread is terminated.
Why does Synchronize()
hang? How do I fix this?
Update
I found a similar question, which explains why Synchronize()
hangs; because CheckSynchronize()
isn't called.
C++Builder 1 doesn't have a CheckSynchronize()
function, nor does TApplication::Idle()
seem to check anything related to thread synchronization.
I still have no idea how to fix this.