I have a simple question about where to use synchronization when communicating with the user through a Main Form in a multi-threaded application.
I've learned that in multi-threaded apps, to give feedback to the user, we must synchronize before the use of visual components on the Main UI thread .
The way I've done it for this project is to have a method in my MainForm called Log. The member FNow is a date string created in the MainForm ctor and updated in a TTimer. Likewise the FLogFile member is created in the ctor, and is a unique_ptr<TBufferedFileStream>. Here's the code for the MainForm->Log(Str) method.
//---------------------------------------------------------------------------
void __fastcall TMainForm::Log(String logStr)
{
TThread::Queue( NULL, [ this, logStr ]() {
String nowLog = "[" + FNow + "]: " + logStr;
if( ShowLogChk->Checked )
Memo->Lines->Append( nowLog );
FLogFile->Write(nowLog.BytesOf() , nowLog.Length());
});
}
The MainForm->Log() method is called from various other objects including inside of TTask's and may possibly be called in a TThread, really anywhere I need to give feedback to the user. For example, this is how it's currently used.
_di_ITask FetchTask = TTask::Create([this, AKey]()
{
MainForm->Log("Widget Task is starting...");
SomeObject->CreateNewWddiget(qryFDQuery, AKey);
});
FetchTask->Start();
My question is, does anyone see an issue with doing it this way, or would it be better to Queue the call where it is used, for example?
void __fastcall TSomeClass::AlertMainForm(String str)
{
TThread::Queue(NULL, [this, str]() {
MainForm->Memo->Lines->Add("Alerting main form: " + str);
});
}
If do it 2nd way, I'm reusing the same code multiple times and creating more chances of bugging out?