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?