Threading in object-oriented, event-driven application

network drift

I need to spawn a thread when a certain trigger event is received inside of a class Foo. The trigger event is received by a Winsock server class that has a reference to the variable triggerEvent.

bool Foo::HandleEvents()
{
    while (1)
    {
        // Other things are done at the top of this loop

        switch (triggerEvent)
        {
            case 'h':
            {
                // I instantiate an object here to do 
                // what I need to do in the thread.
                // I use a pointer that is a private
                // member of Foo.
                thingMaker = new ThingMaker(params);

                // Spawn a new thread here calling a
                // function of ThingMaker and using thingMaker
                break;
            }
            case ...: return true;
            default: break;
        }
    }
}

Since the thread is local to its case in the switch, I lose access to it on break. I can't call join() because I'm dealing with real-time processing and cannot wait for the thread to finish unless I know it's already done.

I recently asked a question about threading here regarding the same application and was told detach() is bad practice; I also think my question was too vague as the solution offered ended up not fitting my needs and my application has since changed in architecture.

I have also tried to encapsulate the thread in short-life manager class that creates instances of ThingMaker but to no avail.

How do I go about this? I suspect my main issue is scope, but my options are limited. Foo::HandleEvents() cannot be delayed at all or else I lose critical data.

txtechhelp

You could use a std::map (or one of the other similar containers):

class Foo
{
    bool HandleEvents();
    std::map<ThingMaker*, std::thread> m_map;
};

bool Foo::HandleEvents()
{
    while (1)
    {
        switch (triggerEvent)
        {
            case 'h':
            {
                thingMaker = new ThingMaker(params);
                m_map[thingMaker] = std::thread(function_ptr, thingMaker);
            } break;
            case 't': // termination event trigger
            {
                m_map[thingMaker].second.join();
                m_map.erase(thingMaker);
                delete thingMaker;
            } break;
            case ...: return true;
            default: break;
        }
    }
}

Since this obviously isn't your full code you'd have to adjust the above code to fit your needs, but you could swap the map's key/value in the template, or use the thread ID instead if that would make more sense (e.g. std::map<std::thread::id, ThingMaker*>, etc.), but something like a map avoids iterating over an array and joining on each thread or having to implement a full thread pool implementation if you don't necessarily need one.

Side note: the use of detach is not bad, in fact it's quite useful; detaching a thread signals to the kernel that the thread can be "cleaned up" as soon as it's done executing (which releases certain resources and handles). Calling detach on a thread is useful when you know you will no longer need access to the underlying thread handle (like in an extremely short lived thread). It's neither bad nor good, simply a tool to utilize (like the infamous goto statement).

Hope that can help.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

TOP Ranking

HotTag

Archive