MessageManagerLock vs/or callAsync


#1

I’ve got an app with many threads doing some network tasks. I need to fire a callback from the thread to the message loop - well known scheme. I finished with two solutions working equally ok but I’m not sure if they are 100% safe. First uses MessageManagerLock, second MessageManager::callAsync:

1:

void TheThread::run()
{
     gatherData(data);
     MessageManagerLock mml (Thread::getCurrentThread());
     while (!mml.lockWasGained() && !threadShouldExit())
     {
         // wait...
     }
     if (!threadShouldExit())
         callback(data);
}

2:

void TheThread::run()
{
     gatherData(data);
     if (!threadShouldExit())
         MessageManager::callAsync ([this]{ callback(data); });    
}

The second is more elegant but does it always guarantee the messages will be delivered? In the first solution is it safe to check lockWasGained() in the thread’s internal loop? Tested both and so far no difference and no errors.


#2

In the second scenario you will need a flag, if the callback has happened, otherwise you start overwriting the gathered data before it was processed by the callback, since it is only scheduled, but can happen after some long unfortunate message thread hickup, which can happen…

Probably a WaitableEvent before gatherData, which is released after the callback happened would be a solution:

void TheThread::run()
{
    waitable.wait();
    gatherData(data);
    if (!threadShouldExit())
        MessageManager::callAsync ([this]{ 
            callback(data);
            waitable.signal(); 
        });    
}

So I think it is guaranteed to happen, just not when…


#3

Thanks, that’s good idea if one needs to keep the data once. But I need to gather all data coming and cannot block the thread. So I will rather create Array as a local variable, add coming data to this array and will check if some data was added using Timer from the main thread.


#4

Yes, that makes sense. Just be aware, that you cannot have it local inside the loop, since callAsync() happens later.
Using a ReferenceCountedObject as data would be a solution, so a captured Ptr would hold the data until the callback has finished.


#5

Yes. Or even simpler: I will not use callback at all, just gather data in the threads’ local arrays and check their data periodically using Timer in the main thread.