1

TL;DR: How should I structure my C++ project to allow for starting, stopping, and pausing my program?

Overview:

I am designing an application that needs to allow users to start, pause, and stop the running of a test. The test functionality itself will be fairly straightforward, but the architecture around it has been a challenge. The program is written on Linux, in C++, using QT for UI and NetBeans for the IDE.

My high level design is as follows:

  1. Execution FIFO with action IDs. Actions will be generated from a custom XML configuration file
  2. When the program is started, the "PC" (program counter) will begin executing actions from the FIFO, keeping track of the current and next action
  3. If the pause button is pressed, the PC will cease to increment to allow users to view the status of various aspects of the test (think a break point)
  4. If the start button is pressed, the PC resumes
  5. If the stop button is pressed, the PC will be set to a figurative "-1" to represent non-running

My specific questions are:

Does logic like this make sense?

while notStopped
    if notPaused
        load action from fifo
        execute action
        pop
    else
        display paused / breakpoint data

Where should an execution like above (or revised) reside? Is main an appropriate location? Is a giant loop the best practice for this use case?

Where should "global" data go? Obviously global variables aren't an option, but how will all aspects of the program understand they are "paused" or "stopped"?

4

If it's understood that pauses don't take effect until the current action is finished, then the other parts of the program shouldn't care what the start/stop/pause condition is. They do nothing until you call them from your central dispatcher.

I'm not sure I'd do this in Main as opposed to some dispatcher object that can be reused. You could have it accept an iteration object containing whatever action you need taken.

1

In terms of stopping and starting; the best way to handle this with the Qt framework are with a Signal/Slot architecture.

The primary advantage to this is that it will thread out this process so your program, and can be easily controlled by emitting signals.

Thus:

while notStopped
    if notPaused
        load action from fifo
        execute action
        pop
    else
        display paused / breakpoint data

can be achieved with an architecture like this:

static bool isPaused(false);
static QEventLoop pauseTesting;


QObject::connect(pause, &QAction::triggered,[&](){
    isPaused = true;
}
QObject::connect(resume, &QAction::triggered,[&](){
    isPaused = false;
    pauseTesting.exit();
}

void breakpoint(QString debug="")
{
    if (isPaused) {
        qDebug() << debug; 
        pauseTesting.exec();
    }
}

void myTest() 
{
    qDebug() << "action 1";
    breakpoint();
    qDebug() << "action 2";
    breakpoint();
    qDebug() << "action 3";
    breakpoint();
    qDebug() << "action 4";
    breakpoint();
}

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.