孝义网站开发公司,wordpress 商城插件,wordpress 当前用户id,注册安全工程师建设工程网站单例模式通常被归类为创建型设计模式#xff0c;因为它主要关注如何创建对象的实例#xff0c;以及如何确保在整个应用程序生命周期中只有一个实例存在。 1.为什么日志模块和数据库连接池需要单例模式 使用单例模式来实现数据库连接池主要有以下几个原因#xff1a; 全局唯… 单例模式通常被归类为创建型设计模式因为它主要关注如何创建对象的实例以及如何确保在整个应用程序生命周期中只有一个实例存在。 1.为什么日志模块和数据库连接池需要单例模式 使用单例模式来实现数据库连接池主要有以下几个原因 全局唯一性数据库连接池在应用程序中通常是一个全局资源多个部分都需要共享同一个连接池。使用单例模式可以确保整个应用程序中只存在一个数据库连接池的实例避免了资源浪费和连接冲突。 统一管理单例模式可以提供一个统一的访问点来管理数据库连接池使得连接的创建、释放和管理更加方便和可控。 避免资源竞争在多线程环境下如果每次请求都创建一个新的连接池实例可能会导致资源竞争和线程安全问题。使用单例模式可以避免这种情况确保连接池的唯一性和线程安全性。 节省资源数据库连接池是一种重量级对象频繁地创建和销毁连接池实例会消耗大量系统资源而单例模式可以确保连接池的唯一性节省了系统资源的开销。 全局唯一性 日志模块是应用程序中的重要组成部分通常在整个应用程序中都需要被访问和使用。使用单例模式可以确保在应用程序的生命周期内只存在一个日志模块实例避免了资源的重复创建和浪费。 统一管理 单例模式提供了一个统一的访问点可以方便地管理日志记录。所有对日志模块的操作都通过单例对象进行使得管理和维护更加简单和可控。 避免资源竞争 在多线程环境下如果多个线程同时尝试创建日志模块实例可能会导致资源竞争和线程安全问题。单例模式可以确保在并发情况下只创建一个实例避免了资源竞争和线程安全性问题。 节省资源 日志模块通常是一种重量级对象频繁地创建和销毁会消耗大量系统资源。使用单例模式可以确保只有一个实例存在节省了系统资源的开销。 一致性和可靠性 使用单例模式可以确保日志记录的一致性和可靠性。由于只有一个日志模块实例存在所有的日志记录都会经过同一个对象不会出现不一致或漏掉日志的情况。 2. 饿汉式单例模式 它在类加载时就创建了实例对象并且在整个程序的生命周期中始终存在。这种方式的单例模式在多线程环境下是线程安全的因为实例对象在类加载时就已经创建好了不会出现多个线程同时创建实例的情况。
// 饿汉单例 一定是安全的
class Singleton{
public:static Singleton* getInstance(){ // 3. 获取类的唯一实例对象的接口方法return instance;}private:static Singleton instance; // 2. 定义一个唯一的类的实例对象Singleton(){ // 1. 构造函数私有化}Singleton(const Singleton) delete; //4.禁止拷贝构造 Singleton 引用类型Singleton operator (const Singleton)delete; // 5. 禁止赋值函数};
Singleton Singleton::instance; // 在数据段main函数启动前已经初始化好了但是影响启动时间构造函数用不了比如加载文件int main(){Singleton *p1 Singleton::getInstance();std::cout p1 std::endl;return 0;
}
3. 懒汉模式 懒汉式单例模式是一种延迟实例化的单例模式实现方式在第一次被调用时才会创建实例对象。与饿汉式单例模式不同懒汉式单例模式的实例对象在需要时才被创建因此称为懒汉。 class Singleton{
public:// 是不是可重入函数 锁 双重判断static Singleton* getInstance(){ // 3. 获取类的唯一实例对象的接口方法if (instance nullptr) {std::lock_guardstd::mutex lock(mutex);/*开辟空间给instance 赋值构造对象*/if (instance nullptr) {instance new Singleton();}}return instance;}private:/*volatile 关键字是一种类型修饰符用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile 提醒编译器它后面所定义的变量随时都有可能改变因此编译后的程序每次需要存储或读取这个变量的时候都会直接从变量地址中读取数据。如 果没有 volatile 关键字则编译器可能优化读取和存储可能暂时使用寄存器中的值如果这个变量由别的程序更新了的话将出现不一致的现象。所以遇到这个关键字声明的变量编译器对访问该变量的代码就不再进行优化从而可以提供对特殊地址的稳定访问。##########################################################################################cpu为了加速访问会将内存的值拷贝一份到寄存器中加入volatile*/static Singleton *volatile instance; // 2. 定义一个唯一的类的实例对象// 用于保护多线程环境下的线程安全static std::mutex mutex;Singleton(){ // 1. 构造函数私有化}Singleton(const Singleton) delete; //4.禁止拷贝构造 Singleton 引用类型Singleton operator (const Singleton)delete; // 5. 禁止赋值函数};
Singleton*volatile Singleton::instance nullptr;
std::mutex Singleton::mutex;int main(){Singleton *p1 Singleton::getInstance();std::cout p1 std::endl;return 0;
}
class Singleton{
public:static Singleton* getInstance(){ // 3. 获取类的唯一实例对象的接口方法static Singleton instance; // 2. 定义一个唯一的类的实例对象// 函数的静态局部变量的初始化在汇编指令上已经自动添加线程互斥指令了return instance;}private:Singleton(){}Singleton(const Singleton) delete; //4.禁止拷贝构造 Singleton 引用类型Singleton operator (const Singleton)delete; // 5. 禁止赋值函数};
3. 可重入函数 可重入函数是指在多线程环境下能够安全地被多个线程同时调用的函数。具体来说可重入函数满足以下两个条件之一或两者兼具
函数不使用静态变量或全局变量包括静态局部变量或者使用这些变量时通过互斥锁或其他同步机制来保护变量的访问。函数使用的静态变量或全局变量只读或者在使用时通过互斥锁或其他同步机制来保护变量的访问。 在多线程环境下如果一个函数不满足上述条件之一那么当多个线程同时调用该函数时就会出现数据竞争和不确定的行为导致程序的行为变得不可预测甚至引发崩溃。 编写可重入函数的关键是避免共享可变状态或者在共享状态时采取适当的同步措施以确保线程安全性。这可能涉及到使用局部变量而不是静态变量或全局变量使用线程局部存储Thread-Local StorageTLS等技术来避免共享状态以及使用互斥锁、信号量、原子操作等同步机制来保护共享状态的访问。
#include iostream
#include mutex// 可重入函数示例
int reentrantFunction(int value) {// 局部变量线程私有不会造成数据竞争int result 0;result value * 2;return result;
}int main() {// 多个线程同时调用可重入函数int result1 reentrantFunction(5);int result2 reentrantFunction(10);// 打印结果std::cout Result 1: result1 std::endl;std::cout Result 2: result2 std::endl;return 0;
}