0

I'm writing a Singleton class in C++ for an ESP32 using ESP-IDF (which uses FreeRTOS). At the moment, he class effectively just has a FreeRTOS mutex and controls access to that mutex. I would like instantiation of this object to be thread-safe. ChatGPT suggested something like this to stay thread safe:

MyClass.h

#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"

class MyClass {
    public:
        static BaseType_t takeMutex(uint32_t blockTime_ms);

        static void giveMutex();

        static MyClass* getInstance();

        MyClass(MyClass &other) = delete;             // Not clonable
        void operator=(const MyClass &) = delete;     // Not assignable

    protected:
        static SemaphoreHandle_t classMutex;
        static MyClass* _instance;

        MyClass();

        void initializeClass();

        static SemaphoreHandle_t& getInstanceCreationMutex();
};

MyClass.cpp

// Static data members are initialized here
SemaphoreHandle_t MyClass::classMutex = nullptr;
MyClass* MyClass::_instance = nullptr;


BaseType_t MyClass::takeMutex(uint32_t blockTime_ms) {
    return xSemaphoreTake(MyClass::classMutex, blockTime_ms/portTICK_RATE_MS);
}


void MyClass::giveMutex() {
    xSemaphoreGive(MyClass::classMutex);
}


MyClass* MyClass::getInstance() {
    xSemaphoreTake(MyClass::getInstanceCreationMutex(), portMAX_DELAY);
    if(MyClass::_instance == nullptr) {
        MyClass::_instance = new MyClass();
    }
    xSemaphoreGive(MyClass::getInstanceCreationMutex());
    return MyClass::_instance;
}


MyClass::MyClass() {
    this->initializeMyClass();
    MyClass::classMutex = xSemaphoreCreateMutex();
}


void MyClass::initializeClass() {
    // Initialization stuff
}


SemaphoreHandle_t& MyClass::getInstanceCreationMutex() {
    static SemaphoreHandle_t mutex = xSemaphoreCreateMutex();
    return mutex;
}

Places like The Refactoring Guru suggest that you use a mutex to lock access to the conditional in getInstance(). However, since FreeRTOS requires a one time setup of a mutex (which might take some time and defeat the purpose of what I'm trying to do), it kind of feels like I have an additional singleton to manage the mutex of the creation of my first singleton. However, I'm worried that that singleton might take long enough to instantiate that it won't be thread safe.

Am I missing something here? Should I use something like a static bool in place of a mutex in hopes that it is faster? Or am I worried about nothing because the creation of mutexes with FreeRTOS is actually really fast?

georgev93
  • 21
  • 1
  • 1
    Make `static MyClass* _instance;` a local variable inside the function `getInstance` and the compiler guarantees its initialization is thread-safe. – 273K Jun 02 '23 at 00:42
  • 1
    If you just want thread safe initialization, use a Meyer's Singleton. https://laristra.github.io/flecsi/src/developer-guide/patterns/meyers_singleton.html – NathanOliver Jun 02 '23 at 00:44
  • Basically the same as above. If you have C++11 support (and it 's 2023 so you sure as should by now for any new product development), [thread-safe singleton comes free out of the box](https://stackoverflow.com/a/1008289/4581301). – user4581301 Jun 02 '23 at 00:53

0 Answers0