C++ 设计模式-单例模式

发布于:2025-02-13 ⋅ 阅读:(11) ⋅ 点赞:(0)

以下是一个使用 C++ 实现的线程安全单例模式示例,结合配置管理器的经典场景,并附带完整测试代码:

#include <iostream>
#include <unordered_map>
#include <mutex>
#include <thread>
#include <vector>
#include <cassert>

// 配置管理器单例类
class ConfigurationManager {
private:
    // 私有化默认构造函数
    ConfigurationManager() = default;
    
    // 删除拷贝构造函数和赋值运算符
    ConfigurationManager(const ConfigurationManager&) = delete;
    ConfigurationManager& operator=(const ConfigurationManager&) = delete;

    // 配置存储容器
    std::unordered_map<std::string, std::string> configs_;
    mutable std::mutex mutex_;

public:
    // 获取单例实例的引用(C++11 起静态局部变量初始化是线程安全的)
    static ConfigurationManager& getInstance() {
        static ConfigurationManager instance;
        return instance;
    }

    // 设置配置项
    void setConfig(const std::string& key, const std::string& value) {
        std::lock_guard<std::mutex> lock(mutex_);
        configs_[key] = value;
    }

    // 获取配置项
    std::string getConfig(const std::string& key) const {
        std::lock_guard<std::mutex> lock(mutex_);
        auto it = configs_.find(key);
        return it != configs_.end() ? it->second : "";
    }

    // 打印所有配置(测试用)
    void printAllConfigs() const {
        std::lock_guard<std::mutex> lock(mutex_);
        std::cout << "Current Configurations:\n";
        for (const auto& pair : configs_) {
            std::cout << pair.first << " = " << pair.second << "\n";
        }
    }
};

// 测试单例模式的基本功能
void testBasicFunctionality() {
    auto& config = ConfigurationManager::getInstance();
    
    // 测试设置和获取配置
    config.setConfig("ServerIP", "192.168.1.100");
    config.setConfig("Port", "8080");
    
    // 验证配置存储
    assert(config.getConfig("ServerIP") == "192.168.1.100");
    assert(config.getConfig("Port") == "8080");
    
    // 测试单例实例的唯一性
    auto& anotherRef = ConfigurationManager::getInstance();
    assert(&config == &anotherRef);
    
    // 修改配置并验证
    anotherRef.setConfig("Timeout", "5000");
    assert(config.getConfig("Timeout") == "5000");
    
    std::cout << "Basic functionality tests passed!\n";
}

// 多线程测试函数
void threadTest(int threadId) {
    auto& config = ConfigurationManager::getInstance();
    
    // 写入线程特定的配置
    config.setConfig("Thread" + std::to_string(threadId), 
                    "Data" + std::to_string(threadId));
    
    // 验证单例地址一致性
    static std::mutex coutMutex;
    {
        std::lock_guard<std::mutex> lock(coutMutex);
        std::cout << "Thread " << threadId 
                  << " instance address: " << &config << "\n";
    }
}

// 多线程测试
void testMultithreadedAccess() {
    constexpr int numThreads = 5;
    std::vector<std::thread> threads;
    
    // 创建多个线程访问单例
    for (int i = 0; i < numThreads; ++i) {
        threads.emplace_back(threadTest, i);
    }
    
    // 等待所有线程完成
    for (auto& t : threads) {
        t.join();
    }
    
    // 验证所有线程写入的配置
    auto& config = ConfigurationManager::getInstance();
    for (int i = 0; i < numThreads; ++i) {
        const std::string key = "Thread" + std::to_string(i);
        assert(config.getConfig(key) == "Data" + std::to_string(i));
    }
    
    std::cout << "Multithreaded tests passed!\n";
}

int main() {
    // 运行基本功能测试
    testBasicFunctionality();
    
    // 运行多线程测试
    testMultithreadedAccess();
    
    // 打印最终配置状态
    std::cout << "\nFinal configuration state:\n";
    ConfigurationManager::getInstance().printAllConfigs();
    
    return 0;
}

代码说明

  1. 单例实现特点

    • 使用静态局部变量实现(C++11 起线程安全)
    • 删除拷贝构造函数和赋值运算符
    • 使用互斥锁保证配置操作的线程安全
    • 提供配置管理的基本接口(设置、获取、打印)
  2. 测试内容包括

    • 单例实例唯一性验证
    • 基本配置操作测试
    • 多线程并发访问测试
    • 线程安全验证(配置项的并发读写)
  3. 经典场景应用

    • 作为配置管理器,集中管理应用程序的配置信息
    • 支持多线程环境下的安全访问
    • 全局唯一访问点保证配置一致性

测试输出示例

Basic functionality tests passed!
Thread 0 instance address: 0x1008b4050
Thread 2 instance address: 0x1008b4050
Thread 1 instance address: 0x1008b4050
Thread 3 instance address: 0x1008b4050
Thread 4 instance address: 0x1008b4050
Multithreaded tests passed!

Final configuration state:
Current Configurations:
Thread4 = Data4
Thread3 = Data3
Thread2 = Data2
Thread1 = Data1
Thread0 = Data0
Timeout = 5000
Port = 8080
ServerIP = 192.168.1.100

该实现通过了以下关键验证:

  1. 所有获取的实例地址相同
  2. 多线程并发访问安全
  3. 不同线程写入的数据完整保存
  4. 基础配置功能正常工作

这个实现方案适用于需要全局统一配置管理的场景,如服务器参数配置、应用程序设置管理等,能够有效保证配置数据的一致性和线程安全性。