1
\$\begingroup\$

I have a large multi-window GUI program (implemented with MFC) that controls a variety of physics experiment apparatus. When the user starts the main function of the program (the "experiment" run), a large worker thread starts which needs references various singleton objects (generally one per piece of apparatus) to do it's work - in particular programming a variety of machines. These objects are in general managed by the windows which contain the GUI elements relative to those objects, and because they are tied to the GUI windows, they will always exist as long as the program is running. I'm struggling to figure out the best way to handle the references to these objects. What I've done in the past is just use raw pointers to these objects, but this seems like bad style so I'm looking at improvements.

My current scheme is having class structures like this:

#include "RF_Generator.h"
#include "AnalogOutputs.h"

struct MasterThreadInput
{
    MasterThreadInput(RfWindow& rfWin, AnalogOutputWindow& aoWin) : 
        objA(winA.getObjA()), 
        objB(winB.getObjB())
    {    }
    RfGenerator& rfSys;
    AnalogOutputs& aoSys;
}

class RfWindow : public CDialog
{
public:
    RfGenerator& getRfSys();
private:
    RfGenerator rfSys;
}

class AnalogOutputWindow : public CDialog
{
public:
    AnalogOutputs& getAoSys();
private:
    AnalogOutputs aoSys;
}

This then gets filled and used like this:

void startThread(RfWindow& rfWin, AnalogOutputWindow& aoWin)
{
    MasterThreadInput* input = new MasterThreadInput(rfWin, aoWin);
    // other checks on the input
    _beginthreadex( NULL, NULL, &MainExperimentThreadProcedure, input, NULL, NULL );
}


unsigned int __stdcall MainExperimentThreadProcedure( void* voidInput )
{
    MasterThreadInput* input = (MasterThreadInput*)voidInput;
    try
    {
        // And then do work.
        input->rfSys.programRfGeneration();
        input->aoSys.programAnalogOutputs();
        // etc.
    }
    catch (...)
    { 
        // handle errors
    }
    delete input;
    return 0;
}

This example code should be very representative of the real thing, except that in the real thing there are 5 windows, many more objects to fill (about 15 in total), and a much more complicated thread procedure - it's a big worker thread. I thought about using smart pointers instead of references considering the seemingly awkward constructor needed to initialize the references, and since I was using raw pointers before these references. However, considering that I don't actually need the worker thread to manage the memory for these objects (the objects will exist as long as the windows do, and the windows will exist for the entire program), it seems that I should just try to avoid pointers all-together. Does this code follow best practices regarding managing memory and shared access in multitheaded c++ applications? Are there ways to improve on this organization? It's a very important part of the control system, so I'd like to get it right.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.