公司外文网站制作常用域名大全
- 作者: 五速梦信息网
- 时间: 2026年03月21日 11:09
当前位置: 首页 > news >正文
公司外文网站制作,常用域名大全,营销网站 app开发,温州网页设计美工文章目录 回顾单例模式0.多线程下的单例模式的意义1.什么是单例模式1.0设计模式1.1C单例模式的介绍及原理1.2拷贝构造和赋值重载的处理1.3if (nullptr ptr)#xff0c;nullptr放在比较运算符的前面?1.4实现单例模式的方式 2.实现懒汉方式的单例模式2.1单线程的单例模式2.2多… 文章目录 回顾单例模式0.多线程下的单例模式的意义1.什么是单例模式1.0设计模式1.1C单例模式的介绍及原理1.2拷贝构造和赋值重载的处理1.3if (nullptr ptr)nullptr放在比较运算符的前面?1.4实现单例模式的方式 2.实现懒汉方式的单例模式2.1单线程的单例模式2.2多线程的单例模式 3.总结线程池4.代码singleThreadPool.hppsingleTestMain.cc 回顾单例模式
在cpp专栏我们已经讲过单例模式。特殊类设计[下] — 单例模式
0.多线程下的单例模式的意义
在多线程环境下单例模式的目的是确保无论有多少线程尝试访问或创建类的实例都只有一个实例被创建并且这个实例可以被所有线程共享和访问。这是因为在多线程编程中如果没有适当的同步机制多个线程可能同时尝试创建类的实例从而导致产生多个实例这与单例模式的初衷相违背。
单例模式在多线程环境下的实现需要特别注意线程安全性。如果没有正确的同步多个线程可能会同时检查单例是否已经被创建并且都得出否定的结论从而都尝试创建新的实例。这会导致产生多个实例破坏单例模式的约束。
因此多线程下的单例模式的主要目的是
确保唯一性不论何时何地整个应用程序范围内都只有一个类的实例存在。 线程安全确保在多线程环境下类的实例的创建和访问都是安全的不会出现数据竞争或不一致的情况。 全局访问点提供一个全局的访问点来获取这个唯一的实例使得任何需要的地方都可以方便地获取和使用这个实例。 为了实现线程安全的单例模式通常需要使用互斥锁如std::mutex或其他同步机制来确保在创建实例时的线程安全。这样即使多个线程同时尝试访问或创建单例也只有一个线程能够成功创建实例而其他线程将获取已经创建好的实例。
1.什么是单例模式
1.0设计模式 IT行业这么火, 涌入的人很多. 俗话说林子大了啥鸟都有. 大佬和菜鸡们两极分化的越来越严重. 为了让菜鸡们不太拖大佬的后腿, 于是大佬们针对一些经典的常见的场景, 给定了一些对应的解决方案, 这个就是 设计模式
1.1C单例模式的介绍及原理
单例模式是一种 “经典的, 常用的, 常考的” 设计模式.
单例模式是一种设计模式它保证一个类仅有一个实例并提供一个全局访问点来访问该实例。这种模式在许多场景下都很有用例如你可能需要一个唯一的配置管理器、资源管理器或线程池。
在C中实现单例模式的基本原理如下
将类的构造函数设为私有以防止外部代码通过new来创建类的实例。 在类内部提供一个静态的私有成员变量来保存类的唯一实例。 提供一个公开的静态成员函数通常命名为getInstance或Instance用于返回类的唯一实例。如果实例尚未创建该函数将负责创建它。 实现一个简易的单例模式至少要具备的条件
要实现一个简易的单例模式你需要满足以下条件
私有构造函数确保类的实例不能从类外部被创建。 静态私有成员变量用于存储类的唯一实例。 公开的静态成员函数用于获取类的唯一实例。这个函数应该在第一次被调用时创建实例并在后续的调用中返回已创建的实例。 以下是一个简单的C用懒汉模式的单例模式实现示例
cpp
class Singleton {
private: // 私有构造函数防止外部创建实例 Singleton() {} // 静态私有成员变量保存唯一实例 static Singleton* instance; public: // 公开的静态成员函数用于获取唯一实例 static Singleton* getInstance() { if (!instance) { instance new Singleton(); } return instance; } // 假设的某个成员函数 void someFunction() { // … } // 析构函数设为公有但通常不需要外部直接调用 ~Singleton() { // 清理资源 }
};
// 初始化静态成员变量
Singleton* Singleton::instance nullptr;在这个示例中Singleton类只有一个私有构造函数因此不能从类外部创建其实例。getInstance函数是获取Singleton类唯一实例的入口点。如果instance为nullptr即尚未创建实例则getInstance会创建一个新的实例。在后续调用中getInstance将直接返回已创建的实例。
注意上述实现不是线程安全的。在多线程环境下多个线程可能同时检查instance是否为nullptr并尝试创建实例从而导致创建多个实例。为了解决这个问题可以使用互斥锁如std::mutex或其他同步机制来确保在任意时刻只有一个线程可以执行创建实例的代码。此外为了避免内存泄漏通常还需要提供一个全局的清理函数来删除单例实例。
1.2拷贝构造和赋值重载的处理
在C单例模式的实现中拷贝构造函数和赋值操作符通常是不需要的因此将它们设为私有并禁止外部使用是一个常见的做法。这是因为单例模式要求一个类只有一个实例而拷贝构造和赋值操作会允许创建类的多个实例这与单例模式的原则相违背。
对于拷贝构造函数你可以这样处理
cpp
class Singleton {
private: // 禁止拷贝构造 Singleton(const Singleton) delete; // … 其他成员 …
};对于赋值操作符你也可以禁止它
cpp
class Singleton {
private: // 禁止赋值操作 Singleton operator(const Singleton) delete; // … 其他成员 …
};delete是C11引入的特性用于显式地禁止某个成员函数的使用。编译器将尝试调用这些函数时会产生编译错误。
通过禁止拷贝构造和赋值操作你确保了单例模式的正确性因为即使尝试进行拷贝或赋值编译器也会阻止这样的操作。
此外对于单例模式来说还需要考虑线程安全的问题。在多线程环境下需要确保getInstance函数的线程安全性以避免多个线程同时创建实例。这通常可以通过使用互斥锁如std::mutex或其他同步机制来实现。
最后为了防止内存泄漏你可能还需要在程序结束时删除单例实例。这可以通过在单例类中添加一个静态的清理函数来实现该函数在程序结束时调用单例实例的析构函数。但是请注意在现代C中通常依赖智能指针如std::shared_ptr和程序终止时的全局对象析构顺序来自动管理单例实例的生命周期而不需要显式地编写清理代码。
1.3if (nullptr ptr)nullptr放在比较运算符的前面?
在C中将nullptr放在比较运算符或!的前面是一种良好的编程习惯尤其是在与指针进行比较时。这样做的好处主要体现在两个方面
防止误写为赋值运算符 将nullptr放在前面可以防止你不小心将比较运算符误写为赋值运算符。如果nullptr在后面例如ptr nullptr当你意图进行比较而误写为赋值时编译器不会产生错误但代码的逻辑会完全改变。这可能导致难以察觉的逻辑错误。通过将nullptr放在前面你可以更容易地识别和纠正这种错误因为nullptr ptr这样的写法在语法上是错误的编译器会立即报错。
代码一致性和可读性 将常量放在比较运算符的左边可以增强代码的一致性。在C中常量通常应该放在比较运算符的左侧这样可以使代码看起来更加统一和整洁。此外这种写法也符合一些编程规范和风格指南有助于提高代码的可读性。
举个例子假设你有一个指针ptr你应该这样写比较语句
cpp
if (nullptr ptr) { // ptr 是 nullptr
}
而不是这样cpp
if (ptr nullptr) { // ptr 是 nullptr
}虽然第二种写法在逻辑上是正确的但第一种写法提供了额外的安全性防止了可能的误写。
然而值得注意的是现代编译器和IDE通常都有强大的代码检查和重构工具可以帮助你避免这类错误。因此即使你将nullptr放在比较运算符的右侧只要你的编程环境配置得当也可以有效地避免误写为赋值运算符的问题。不过遵循将常量放在比较运算符左侧的约定仍然是一个好习惯因为它可以提高代码的一致性和可读性。
1.4实现单例模式的方式 饿汉实现方式和懒汉实现方式 吃完饭, 立刻洗碗, 这种就是饿汉方式. 因为下一顿吃的时候可以立刻拿着碗就能吃饭。不用的时候就准备好了要用的时候直接拿来用。 吃完饭, 先把碗放下, 然后下一顿饭用到这个碗了再洗碗, 就是懒汉方式.懒汉方式最核心的思想是 “延时加载”. 从而能够优化服务器的启动速度。用的时候再准备。
2.实现懒汉方式的单例模式
2.1单线程的单例模式
static singleThreadPoolT *getThreadPoolInstance(int threadNum g_threadNum)
{if (nullptr ptrThreadPool){ptrThreadPool new singleThreadPoolT(threadNum);}return ptrThreadPool;
}2.2多线程的单例模式
static singleThreadPoolT *getThreadPoolInstance(int threadNum g_threadNum)
{if (nullptr ptrThreadPool){ptrThreadPool new singleThreadPoolT(threadNum);}return ptrThreadPool;
}单线程下的单例模式代码拿到多线程场景中需要考虑的【线程安全问题】只发生在第一次创建单例时即第一次可能有多个线程在执行if语句这样就可能有不止一个线程获取到了单例基于这种情况我们进行了第一步改版。如下。
static singleThreadPoolT *getThreadPoolInstance(int threadNum g_threadNum)
{{lockGuard lockguard(mutex);if (nullptr ptrThreadPool){ptrThreadPool new singleThreadPoolT(threadNum);}}return ptrThreadPool;
}这样并不完全对。我们还要考虑第一次的某个线程成功获取了单例即这个线程拿着指向一个单例对象的ptrThreadPool走了之后的线程再次调用getThreadPoolInstance接口想获取到这个唯一的单例时需要申请锁–执行if–if不满足–解锁–返回ptrThreadPool。问题来了之后的线程虽然没有创建单例但是获取到了这个唯一的单例即之后的线程可以获取到唯一的单例多线程下的单例模式似乎已经搞定了。但是这样会存在大量的申请和释放锁的行为这毫无意义且浪费资源即之后的线程在获取单例时if一定是不满足的这时压根没必要进行加锁和解锁但是为了保证第一次创建单例是安全的加锁的行为必须有之后的线程申请到了锁那还好如果申请不到还要等待⇒ 这毫无意义且浪费资源。做进一步优化如下。
static singleThreadPoolT *getThreadPoolInstance(int threadNum g_threadNum){if (nullptr ptrThreadPool){lockGuard lockguard(mutex);if (nullptr ptrThreadPool){ptrThreadPool new singleThreadPoolT(threadNum);}}return ptrThreadPool;}这样写的优势 假定【后续线程】第一次已经有某个线程创建了单例即单例已存在。那么这样写的优势有效减少后续线程进行加锁检测的问题拦截大量后续线程直接访问锁的行为
3.总结线程池
设计一个线程池这个线程池有多个线程在运行一旦接收到任务则某个线程就会去获取并执行任务。可能有多个线程充当派发任务的一方这时就引入了【单例模式】版的线程池旨在让不同的线程共享唯一的一个线程池实例任务方线程们都向这个单例线程池派发任务。上面的代码我们只创建了一个任务派送方【main线程】但是单例模式我们已经写好了读者们可以创建多个任务派送方测试单例模式是否正确。由于我们设计的主线程是死循环我们并没有维护单例的回收单例的回收我们在特殊类设计[下] — 单例模式已经讲过。
4.代码
其余代码与【Linux】认识线程池 AND 手撕线程池正常版相同点击获取即可。
singleThreadPool.hpp
#pragma once#include iostream
#include vector
#include string
#include queue
#include unistd.h
#include thread.hpp
#include lockGuard.hpp
#include log.hppconst int g_threadNum 3;template class T
class singleThreadPool
{
public:pthread_mutex_t *getMutex(){return lock;}void waitCond(){pthread_cond_wait(cond, lock);}bool isEmpty(){return _taskQueue.empty();}T getTask(){T t _taskQueue.front();_taskQueue.pop();return t;}static void *startRoutine(void *args){ThreadInfo *td (ThreadInfo *)args;singleThreadPoolT *tp (singleThreadPoolT *)td-_ptrThreadPool;while (true){T task;{lockGuard lockguard(tp-getMutex());while (tp-isEmpty())tp-waitCond();task tp-getTask();}task(td-_threadName);}}private:// 构造函数singleThreadPool(int thread_num g_threadNum): _threadNum(thread_num){pthread_mutex_init(lock, nullptr);pthread_cond_init(cond, nullptr);for (int i 1; i _threadNum; i){// 初始化列表区域 对象还未存在 走到函数块{}内 对象已存在 可以使用this指针_threads.push_back(new Thread(i, startRoutine, this));}}singleThreadPool(const singleThreadPoolT copy) delete;const singleThreadPoolT operator(const singleThreadPoolT copy) delete;public:// 考虑 多线程使用单例 的情况static singleThreadPoolT *getThreadPoolInstance(int threadNum g_threadNum){if (nullptr ptrThreadPool){lockGuard lockguard(mutex);if (nullptr ptrThreadPool){ptrThreadPool new singleThreadPoolT(threadNum);}}return ptrThreadPool;}void run(){for (auto iter : _threads){iter-start();// std::cout iter-name() 启动成功 std::endl;logMsg(NORMAL, %s %s, iter-name().c_str(), 启动成功);}}void pushTask(const T task){lockGuard lockguard(lock);_taskQueue.push(task);pthread_cond_signal(cond);}~singleThreadPool(){for (auto iter : _threads){iter-join();delete iter;}pthread_mutex_destroy(lock);pthread_cond_destroy(cond);}private:int _threadNum;std::vectorThread * _threads;std::queueT _taskQueue;pthread_mutex_t lock;pthread_cond_t cond;volatile static singleThreadPoolT *ptrThreadPool;懒汉是调用的时候才会赋值如果创建了对象这个指针实际已经指向了单例如果指针一开始被优化到寄存器里了那第二次后续线程访问这个指针就是null后续不从内存里读取的话就会一直是null了static pthread_mutex_t mutex;
};// 类内声明 类外初始化
template typename T
singleThreadPoolT *singleThreadPoolT::ptrThreadPool nullptr;template typename T
pthread_mutex_t singleThreadPoolT::mutex PTHREAD_MUTEX_INITIALIZER;singleTestMain.cc
#include ctime
#include cstdlib
#include iostream
#include unistd.h#include singleThreadPool.hpp
#include Task.hppint main()
{srand((unsigned long)time(nullptr) ^ getpid());// ThreadPoolTask *tp new ThreadPoolTask();// ThreadPoolTask *tp ThreadPoolTask::getThreadPoolInstance();//tp-run();singleThreadPoolTask::getThreadPoolInstance()-run();while (true){// 生产数据/制作任务 – 耗费时间int x rand() % 10 1;usleep(1000);int y rand() % 5 1;Task t(x, y, - int{ return x y; });logMsg(DEBUG, Main-Pro 发送任务: %d%d未知, x, y);// 推送任务到线程池中// tp-pushTask(t);singleThreadPoolTask::getThreadPoolInstance()-pushTask(t);sleep(1);}return 0;
}
- 上一篇: 公司手机网站设计网站开发定价
- 下一篇: 公司网站 域名wordpress 全文检索
相关文章
-
公司手机网站设计网站开发定价
公司手机网站设计网站开发定价
- 技术栈
- 2026年03月21日
-
公司手机网站开发招标书高级网站开发工程师工资
公司手机网站开发招标书高级网站开发工程师工资
- 技术栈
- 2026年03月21日
-
公司手机网站建设南宁企业网站建站模板
公司手机网站建设南宁企业网站建站模板
- 技术栈
- 2026年03月21日
-
公司网站 域名wordpress 全文检索
公司网站 域名wordpress 全文检索
- 技术栈
- 2026年03月21日
-
公司网站 制作商业空间展示设计
公司网站 制作商业空间展示设计
- 技术栈
- 2026年03月21日
-
公司网站包含哪些内容龙川网站建设
公司网站包含哪些内容龙川网站建设
- 技术栈
- 2026年03月21日
