线程安全单例课程-我这样做正确吗?

时间:2019-03-04 16:19:32

标签: c++ multithreading c++11 singleton

我正在创建一个系统状态类,该类在读取/写入时必须是线程安全的。我正在使用Singleton设计模式来实现它。 我基于这些Stackoverflow问题的指针:

  1. Singleton: How it Should be Used
  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.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 :(得分:1)

您不是惯用的单例,因为它仍然容易发生所谓的“静态初始化顺序惨败”。

惯用单例没有静态类成员,而是其实例函数看起来像

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

有关惨败的更多信息:static initialization order fiasco

答案 1 :(得分:0)

不,这可能在更复杂的情况下不起作用,但不是出于线程安全的原因,而是由于静态对象初始化的不确定行为。

假设您的对象在这里:

static System_State stateInstance;

需要使用另一个静态getInstance检索的另一个静态对象。您无法保证这将返回有效/构造的对象。

如果可以确保该对象不需要其他静态对象,则应该没问题。但这是很多单例构造的问题,在构造构造和线程安全性时必须保持平衡。