muduo网络库源码学习————线程本地单例类封装
muduo库中线程本地单例类封装代码是ThreadLocalSingleton.h
如下所示:
//线程本地单例类封装
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.
//
// Author: Shuo Chen (chenshuo at chenshuo dot com)
#ifndef MUDUO_BASE_THREADLOCALSINGLETON_H
#define MUDUO_BASE_THREADLOCALSINGLETON_H
#include <boost/noncopyable.hpp>
#include <assert.h>
#include <pthread.h>
namespace muduo
{
template<typename T>
class ThreadLocalSingleton : boost::noncopyable//不可被拷贝
{
public:
//返回单例对象的引用
static T& instance()
{
if (!t_value_)//如果指针为空
{
t_value_ = new T();//创建对象
deleter_.set(t_value_);//将t_value_传入deleter_,以便deleter_可以调用destructor销毁
}
return *t_value_;//返回
}
//返回单例对象的指针
static T* pointer()
{
return t_value_;
}
private:
//销毁对象
static void destructor(void* obj)
{
assert(obj == t_value_);
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
delete t_value_;
t_value_ = 0;
}
//一个嵌套类只是为了能够调用destructor自动销毁t_value_
class Deleter
{//借助线程特定数据来实现
public:
Deleter()//构造函数的回调函数为ThreadLocalSingleton::destructor
{
pthread_key_create(&pkey_, &ThreadLocalSingleton::destructor);
}
~Deleter()
{
pthread_key_delete(pkey_);
}
void set(T* newObj)
{
assert(pthread_getspecific(pkey_) == NULL);
pthread_setspecific(pkey_, newObj);
}
pthread_key_t pkey_;
};
static __thread T* t_value_;//T类型的指针,__thread关键字表示每个线程都有一份
static Deleter deleter_;//主要用于销毁上面那个指针所指向的对象
};
template<typename T>
__thread T* ThreadLocalSingleton<T>::t_value_ = 0;
template<typename T>
typename ThreadLocalSingleton<T>::Deleter ThreadLocalSingleton<T>::deleter_;
}
#endif
测试程序如下:
//线程本地单例类封装测试程序
#include <muduo/base/ThreadLocalSingleton.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/Thread.h>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <stdio.h>
class Test : boost::noncopyable
{
public:
Test()
{
printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this);
}
~Test()
{
printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str());
}
const std::string& name() const { return name_; }
void setName(const std::string& n) { name_ = n; }
private:
std::string name_;
};
void threadFunc(const char* changeTo)
{//打印线程tid,线程单例对象地址,线程单例对象名称
printf("tid=%d, %p name=%s\n",
muduo::CurrentThread::tid(),
&muduo::ThreadLocalSingleton<Test>::instance(),
muduo::ThreadLocalSingleton<Test>::instance().name().c_str());
//重新设置一下名称
muduo::ThreadLocalSingleton<Test>::instance().setName(changeTo);
//再次打印
printf("tid=%d, %p name=%s\n",
muduo::CurrentThread::tid(),
&muduo::ThreadLocalSingleton<Test>::instance(),
muduo::ThreadLocalSingleton<Test>::instance().name().c_str());
//线程退出时会自动销毁,对象周期结束
// no need to manually delete it
// muduo::ThreadLocalSingleton<Test>::destroy();
}
int main()
{//muduo::ThreadLocalSingleton<Test>::instance()返回一个线程单例对象,每个线程都有一个Test对象
muduo::ThreadLocalSingleton<Test>::instance().setName("main one");
//创建两个线程,threadFunc为回调函数
muduo::Thread t1(boost::bind(threadFunc, "thread1"));
muduo::Thread t2(boost::bind(threadFunc, "thread2"));
//启动两个线程
t1.start();
t2.start();
t1.join();
//打印主线程的
printf("tid=%d, %p name=%s\n",
muduo::CurrentThread::tid(),
&muduo::ThreadLocalSingleton<Test>::instance(),
muduo::ThreadLocalSingleton<Test>::instance().name().c_str());
t2.join();
//退出主线程
pthread_exit(0);
}
运行结果如下:
muduo网络库源码学习————线程本地单例类封装的更多相关文章
- muduo网络库源码学习————线程特定数据
muduo库线程特定数据源码文件为ThreadLocal.h //线程本地存储 // Use of this source code is governed by a BSD-style licens ...
- muduo网络库源码学习————线程池实现
muduo库里面的线程池是固定线程池,即创建的线程池里面的线程个数是一定的,不是动态的.线程池里面一般要包含线程队列还有任务队列,外部程序将任务存放到线程池的任务队列中,线程池中的线程队列执行任务,也 ...
- muduo网络库源码学习————线程类
muduo库里面的线程类是使用基于对象的编程思想,源码目录为muduo/base,如下所示: 线程类头文件: // Use of this source code is governed by a B ...
- muduo网络库源码学习————线程安全
线程安全使用单例模式,保证了每次只创建单个对象,代码如下: Singleton.h // Use of this source code is governed by a BSD-style lice ...
- muduo网络库源码学习————Timestamp.cc
今天开始学习陈硕先生的muduo网络库,moduo网络库得到很多好评,陈硕先生自己也说核心代码不超过5000行,所以我觉得有必要拿过来好好学习下,学习的时候在源码上面添加一些自己的注释,方便日后理解, ...
- muduo网络库源码学习————互斥锁
muduo源码的互斥锁源码位于muduo/base,Mutex.h,进行了两个类的封装,在实际的使用中更常使用MutexLockGuard类,因为该类可以在析构函数中自动解锁,避免了某些情况忘记解锁. ...
- muduo网络库源码学习————日志滚动
muduo库里面的实现日志滚动有两种条件,一种是日志文件大小达到预设值,另一种是时间到达超过当天.滚动日志类的文件是LogFile.cc ,LogFile.h 代码如下: LogFile.cc #in ...
- muduo网络库源码学习————日志类封装
muduo库里面的日志使方法如下 这里定义了一个宏 #define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) ...
- muduo网络库源码学习————无界队列和有界队列
muduo库里实现了两个队列模板类:无界队列为BlockingQueue.h,有界队列为BoundedBlockingQueue.h,两个测试程序实现了生产者和消费者模型.(这里以无界队列为例,有界队 ...
随机推荐
- Flask 入门(特别篇)
作为一款优秀的编辑器,pycharm得到了很多人的支持,但是刚接触它的小伙伴会遇到一个困难,如何把一个别人做的python项目导入到pycharm里面呢? 1.手动建立一个虚拟环境,注意这个环境和你导 ...
- python 删除三天前的日志.py
#获取所有文件def file(): for cur_dir, dirs, files in os.walk(r'/学习/接口自动化/BestTest/作业/logs'): # cur_dir(当前路 ...
- jvm入门及理解(三)——运行时数据区(程序计数器+本地方法栈)
一.内存与线程 内存: 内存是非常重要的系统资源,是硬盘和cpu的中间仓库及桥梁,承载着操作系统和应用程序的实时运行.JVM内存布局规定了JAVA在运行过程中内存申请.分配.管理的策略,保证了JVM的 ...
- sparkRdd driver和excuter
//1 从内存中创建makeRdd,底层实现就是parallelize val rdd=sc.makeRDD(Array(1,2,"df",55)) //2 从中创建paralle ...
- 数据结构和算法(Golang实现)(5)简单入门Golang-接口
接口 在Golang世界中,有一种叫interface的东西,很是神奇. 一.数据类型 interface{} 如果你事前并不知道变量是哪种数据类型,不知道它是整数还是字符串,但是你还是想要使用它. ...
- 浅谈ArrayList
浅谈ArrayList 废话不多说(事实是不会说),让我们直接进入正题 首先讲一讲最基本的ArrayList的初始化,也就是我们常说的构造函数,ArrayList给我们提供了三种构造方式,我们逐个来查 ...
- 【从零单排HBase 03】深入HBase读写
在了解HBase架构的基础上,我们需要进一步学习HBase的读写过程,一方面是了解各个组件在整个读写过程中充当的角色,另一方面只有了解HBase的真实请求过程,才能为后续的正确使用打下初步基础,毕竟, ...
- 【Tool】使用IDEA创建简单的Java项目
IDEA创建简单的Java项目 打开IDEA进入首页面,点击 Create New Project 点选第一项就是了,SDK就是我们的JDK,,这里我已经装好了JDK和JDK的环境变量 IDEA就能自 ...
- ado.net 面向对象
面向对象:就是一个大的转换器,建立起一条通道通往数据库然后通过通道将所需(方法)数据从转换器往返于外部界面端 1 首先在项目里创建文件夹: 右击项目———添加个文件夹App_Cod 2 ...
- Suctf知识记录&&PHP代码审计,无字母数字webshell&&open_basedir绕过&&waf+idna+pythonssrf+nginx
Checkin .user.ini构成php后门利用,设置auto_prepend_file=01.jpg,自动在文件前包含了01.jpg,利用.user.ini和图片马实现文件包含+图片马的利用. ...