Simplifying VCL thread wrapper code

2019-03-22 03:09发布

问题:

I am using thread wrapper which checks if function which updates VCL (which also has some arguments) was called from main thread or not and then executes in within the context of Main thread always.

It works but I want to make it simpler. The problem is that I have to repeat this code in every function which needs VCL synchronization which is prone to errors. Is there a way to make this wrapper simpler and more re-useable? Note that this particular wrapper only uses one parameter but there can be any number of parameters which are copied to TLocalArgs and passed on.

Current code:

boost::scoped_ptr<TIdThreadComponent> WorkerThread;

...

void TForm1::SetMemoMessage(UnicodeString Msg)
{
// Check which thread called function, main thread or worker thread
if (GetCurrentThreadId() != System::MainThreadID)
    {
    struct TLocalArgs
        {
        TForm1 *Form;
        UnicodeString Msg;
        void __fastcall SetMemoMessage() // Same name as main function to make it easier to maintain
            {
            // We are in main thread now, safe to call message update directly
            Form->SetMemoMessage(Msg);
            }
        };

    // We are in worker thread, wrap into Synchronize
    TLocalArgs Args = { this, Msg };
    WorkerThread->Synchronize(&Args.SetMemoMessage);
    return;
    }

// MAIN THREAD CODE is very simple compared to wrapper above
Memo1->Text = Msg;
}

回答1:

TThread::Synchronize() checks MainThreadID internally for you and calls the specified procedure directly if Synchronize() is called from the main thread. So just call Synchronize() unconditionally and let it handle the details. Synchronize() also has overloaded static versions available so you don't even need a TThread pointer to call it.

Try this:

void TForm1::SetMemoMessage(UnicodeString Msg)
{
    struct TLocalArgs
    {
        UnicodeString Msg;
        void __fastcall SetMemoMessage()
        {
            Form1->Memo1->Text = Msg;
        }
    };

    TLocalArgs Args;
    Args.Msg = Msg;
    TThread::Synchronize(NULL, &Args.SetMemoMessage);
}