-1

I'm trying to create a performance monitor of sorts to run on a Particle board (STM32 based). I'm used to programming in c so the OOP approach is a bit new but I think it would fit well here.

For the purpose of this question let's assume I have two types of monitors:

  1. Frequency. The application can call a "tick" method of the monitor to calculate the time since it last ran and store it.
  2. Period- call a "start" and "stop" method of the monitor to calculate how long a process takes to run and store it.

What I would like to do is to create instances of these monitors throughout my application and be able to report on the stats of all monitors of all types from the main module.

I've read about the singleton design pattern which seems like it might be what I need but I'm not sure and I'm also concerned about thread safety with that.

I'm thinking I will create a "StatMonitor" class and a derived class "FrequencyMonitor" and "PeriodMonitor". Monitor would be a singleton and everywhere I wanted to create a new monitor I would request an instance of "Monitor" and use that like so:

freqMonitor * task1FreqMonitor = StatMonitor::GetInstance()->Add_Freq_Monitor("Task1");

The StatMonitor would track all monitors I've added and when I wanted to print the stats I could just call the printAll method which would iterate it's array of monitors and request their results like so:

StatMonitor::GetInstance()->PrintAllStats();

Am I going down the right path?

spizzak
  • 1,087
  • 1
  • 11
  • 17

1 Answers1

2

Your path sounds good, except that FrequencyMonitor and PeriodMonitor should not derive from the class that "manages" all these monitors (let's call it MonitorPrinter).

MonitorPrinter should be a singleton and could look like this:

class MonitorPrinter
{
public:
    static MonitorPrinter& getInstance()
    {
        static MonitorPrinter monitorPrinter;
        return monitorPrinter;
    }

    void printAllStats()
    {
        for (const auto& [_, frequencyMonitor] : _frequencyMonitors)
            frequencyMonitor.print();
        for (const auto& [_, periodMonitor] : _periodMonitors)
            periodMonitor.print();
    }

    FrequencyMonitor& getFrequencyMonitor(std::string name)
    { return _frequencyMonitors[name]; }
    PeriodMonitor& getPeriodMonitor(std::string name)
    { return _periodMonitors[name]; }

private:
    MonitorPrinter() = default;

    std::map<std::string, FrequencyMonitor> _frequencyMonitors;
    std::map<std::string, PeriodMonitor> _periodMonitors;
};

Demo

(The const auto& [_, frequencyMonitor] is a structured binding).

FrequencyMonitor and PeriodMonitor should not have anything to do with singletons, and from your description, they need not be part of a class hierarchy either (as they have different interfaces). If you want, you can prevent users (other than the MonitorPrinter) from instantiating these classes using other techniques, but I won't elaborate on that here.

In short, there is no need to use OOP here. Use a singleton to provide (and keep track of) the monitors, and implement the monitors to your liking. Be wary of thread safety if this is relevant (the above is not thread-safe!).

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
  • The monitors will likely have a some common methods in their interface (reset stats, get stats, etc.) Would a heirarchy make sense to have then or does it not provide any benefit? – spizzak Jun 07 '19 at 16:46
  • Yes, in that case a hierarchy would make sense. But there is no reason to make the base class also the one that is the singleton - the interfaces and purposes of `MonitorPrinter` and the individual monitors (and their potential base class) are totally different. – Max Langhof Jun 07 '19 at 16:47
  • @spizzak There are cases for `FrequencyMonitor` and `PeriodMonitor` to derive from `Monitor`, but I'm not sure I see any of them having to apply here either. Give a few of the options a shot and see what works best for you. – user4581301 Jun 07 '19 at 16:47
  • 1
    And do not forget our SOLID friend the [Liskov Substitution Principle](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle) – user4581301 Jun 07 '19 at 16:50
  • @MaxLanghof, I've decided to just create a single monitor that tracks both statistics since that will suite my needs. The plan now is to have a singleton "monitor manager" like your MonitorPrinter to provide monitors as needed. What I'm unsure of is how you provide a monitor in your example. Where is the monitor object being created here? – spizzak Jun 11 '19 at 18:34