Потокобезопасный класс Singleton - я делаю это правильно? - PullRequest
0 голосов
/ 04 марта 2019

Я создаю класс состояния системы, который должен быть потокобезопасным при чтении / записи.Я реализую его, используя шаблон проектирования Singleton.Я основал его на указателях из этих вопросов Stackoverflow:

  1. Singleton: как его использовать
  2. C ++ Singleton Design Pattern

Вот сокращенный пример моего кода.По сути, это просто некоторые переменные состояния, которые мне нужно отслеживать и делить между несколькими потоками.Я точно знаю, что когда-либо будет нужен только один экземпляр состояния, и я знаю, что он должен быть безопасным и постоянным.Будет ли эта реализация обеспечивать это?

// System_State.h
class System_State
{
public:
    static System_State &getInstance()
    {
        static System_State stateInstance;
        return stateInstance;
    }

    System_State(System_State const&)   = delete;
    void operator=(System_State const&) = delete;

    // Example Setter with mutex guard
    void setWifiConnectedStatus(uint8_t _status)
    {
        std::lock_guard<std::mutex> lock(mtx);
        Wifi.ConnectedStatus = _status;
    }

private:
    System_State() 
    {
        initializeState();
    }

    void initializeState();

    std::mutex mtx;

    static struct WifiService
    {
        uint8_t     ConnectedStatus;
        std::string CurrentConnection;
        std::string SavedNetworks;
        std::string AvailableNetworks;
        std::string ForgetNetwork;
        std::string ConnectTo;
        std::string DisconnectFrom;
    } Wifi;

    static struct ScanService
    {
        std::string PerformScan;
        std::string ScanStatus;
        uint8_t     ScanProgress;
    } Scan;

    static struct UploadDataService
    {
        std::string PerformUpload;
        uint8_t     UploadProgress;
        uint8_t     ItemsWaitingToBeUploaded;
    } UploadData;

    static std::string LEDControlBrightness;
    static uint8_t     BatteryPercentage;
};

А вот пример main

//main.cpp
#include <thread>

void loop1()
{
    System_State state = System_State::getInstance();
    while(true)
    {
        //do randomness with state
    }
}

void loop2()
{
    System_State state2 = System_State::getInstance();
    while(true)
    {
        //do randomness with state2
    }
}

int main()
{
    std::thread t1(loop1);
    std::thread t2(loop2);
    // do and join and all that!
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

Ваш не является идиоматическим синглтоном, потому что он все еще подвержен так называемому «фиаско статического порядка инициализации».

Идиоматический синглтон не имеет статического члена класса, вместо этого его функция экземпляра выглядит как

static MySingleton& instance() {
    static MySingleton the_ton;
    return the_ton;
}

Подробнее о фиаско: статический порядок инициализации фиаско

0 голосов
/ 04 марта 2019

Нет, это может не работать в более сложном случае, но не из-за безопасности потока, а из-за неопределенного поведения статической инициализации объекта.

Допустим, ваш объект здесь:

static System_State stateInstance;

требуется другой статический объект, который вы получаете с другим статическим getInstance.У вас нет уверенности, что это вернет действительный / построенный объект.

Если вы можете гарантировать, что этот объект не требует другого статического объекта, то у вас все будет хорошо.Но это проблема большого количества одноэлементных конструкций, вы должны уравновесить их, когда они созданы и потокобезопасны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...