[Qt-interest] Initializing application modules in sequence
K. Frank
kfrank29.c at gmail.com
Mon Apr 25 17:54:24 CEST 2011
Hello Mandeep (and Sean)!
On Mon, Apr 25, 2011 at 10:27 AM, Sean Harmer
<sean.harmer at maps-technology.com> wrote:
> Hi,
> On 25/04/2011 14:41, Mandeep Sandhu wrote:
>>> ...
>> ...
>> Won't async/non-blocking init's require some sort of a parallel state
>> group? Take the following init steps eg:
>>
>> 1 (B) -> 2 (B) -> 3 (NB) -> 4 (NB)
>> +-> 5 (B)
>>
>> B=blocking
>> NB=non-blocking
>> ...
>> Another thought that I want to bounce off others:
>>
>> * Have a controller class...say InitManager (initmgr for short).
>> * All modules that need initialization implement an interface so that
>> the initmgr has a uniform way of talking to, with all modules.
>> ...
>>
>> To keep it simple I've removed the requirement of having a
>> 'dependency' though. In case a module 'C' requires module 'A' to be
>> done before, then 'A' must be made blocking and 'C' should be
>> registered _after_ 'A'. So with this limitation, all modules which do
>> not have any dependencies can be marked as non-blocking and others as
>> blocking.
>
> This seems like a hack to achieve what the SM provides naturally.
> ...
If your platform supports threading, you might be able to simplify your
logic with the following approach: Wrap each of your services in a
singleton that initializes itself on demand. Let's say each service is
a class. Then let's say service A depends on services B, D, and F:
ServiceA { // pseudo-code:
static serviceB *b;
static serviceD *d;
static serviceF *f;
static void initB() { b = ServiceB::getInitializedServiceB(); }
static void initD() { d = ServiceD::getInitializedServiceD(); }
static void initF() { f = ServiceF::getInitializedServiceF(); }
static std::mutex singletonMutex;
static bool initialized;
static ServiceA *singletonA;
static *ServiceA getInitializedServiceA() {
std::unique_lock l (singletomMutex); // scoped lock for function body
if (initialized) return singletonA;
std::thread tB (initB);
std::thread tD (initD);
std::thread tF (initF);
tB.join();
tD.join();
tF.join();
// at this point, all of A's immediate dependencies have been initialized
// they have been responsible for initializing their dependencies
singletonA = new ServiceA; // constructor can safely use serviceB, etc.
initialized = true;
return singletonA;
}
Then, if you want to insure that all of your services are initialized at
start-up (rather than on a lazy, as-needed basis):
main () {
std::thread tA (initA);
// any and all service initializations...
std::thread tZ (initZ);
tA.join();
// join the rest of the initialization threads
tZ.join();
// good to go -- everybody initialized at start-up
// launch app...
}
The cost: At start-up you spawn off a bunch of threads to get these
singletons, most of which merely block until some other thread has
initialized the singleton in question.
The advantages: Nobody has to keep track as to whether some
initializations are blocking and others non-blocking, and you still
get maximum benefit of letting "non-blocking" initializations run
simultaneously. No central dependency manager has to keep track
of dependencies or in which order to run the initializations. Each
service needs only know of its immediate dependencies, and,
provided you have no cyclic dependencies (which would cause
you grief in any of the schemes discussed), you get exactly the
ordering of initializations you need. To add a new service, you
only need to provide code for the service itself, only requiring that
the new service initialize its immediate dependencies.
Happy Hacking!
K. Frank
More information about the Qt-interest-old
mailing list