log4cpp源码阅读:threading工具类
发布日期:2022-03-16 03:25:41
浏览次数:17
分类:技术文章
本文共 5996 字,大约阅读时间需要 19 分钟。
threading命名空间
- 位置:位于include/log4cpp/threading目录下
- 相应类都处于threading命名空间下。这个命名空间中包含了一些线程同步的类,以及获取当前线程的方法。还有一个线程作用域局部变量的实现
- 因为线程是一个系统内核对象,并且不同的编译器平台也对线程这个借口进行了不同的封装,所以他有很多种实现,也就是不同平台的具体实现类的名称可能不一样。这里屏蔽了不同提供了同一的名称:Mutex, ScopedLock, ThreadLocalDataHolder, getThreadID
win平台
- 位置:include/log4cpp/threading/MSThreads.xx
Mutex类
- 作用:这个类实现的是互斥量的功能,可以用来保护某些访问是线程安全的。下面看一下他在win32平台上代码的实现。
class MSMutex { public: //在构造器中创建临界区对象 MSMutex() { InitializeCriticalSection(&_criticalSection); } // 在析构器中销毁临界区对象 ~MSMutex() { DeleteCriticalSection(&_criticalSection); } // 返回包装的临界区对象 inline LPCRITICAL_SECTION getCriticalSection() { return &_criticalSection; }private: //禁止拷贝,否则容易出现死锁(因为操作不一致) MSMutex(const MSMutex&); CRITICAL_SECTION _criticalSection; //临界区对象};typedef MSMutex Mutex; // 一个简单非可递归的锁
可以看到,Mutex就是一个MSMutex的别名,MSMutex的实现,内部其实就是包装了一个临界区对象,在对象被构造的时候创建该对象,在对象被析构时销毁该对象。并且提供了一个让用户访问的接口getCriticalSection方法,最后还定义了两个私有的方法来禁止该对象被拷贝
ScopedLock类
//一个作用域局部锁class MSScopedLock { public: //在构造器中进入锁 MSScopedLock(MSMutex &mutex) { _criticalSection = mutex.getCriticalSection(); EnterCriticalSection(_criticalSection); } // 在析构器中释放锁 ~MSScopedLock() { LeaveCriticalSection(_criticalSection); }private: MSScopedLock(const MSScopedLock& other); // 进制对象被拷贝 LPCRITICAL_SECTION _criticalSection; // 内部保存的临界区对象指针};typedef MSScopedLock ScopedLock; // 这儿是定义的ScopedLock的统一名称类型
可以看到ScopedLock的真正类型是MSCopedLock,逻辑很简单,必须要使用Mutex对象进行构造然后进入该临界区对象,然后,再次ScopedLock对象性被析构时,离开临界区,这就能保证某个作用域内的方法是安全的。比如
class Category { public: void addAppender(Appender *appender) { ScopedLock scopedLock(_mutex); _appenders.insert(appender); } void removeAppender(Appender *appender) { ScopedLock scopedLock(_mutex); auto pos = _appenders.find(appender); if (pos != _appenders.end()) { delete appender; _appenders.erase(pos); } }private: Mutex _mutex; std::set_appenders;};
这样实现可以保证对_appenders的访问是线程安全的
ThreadLocalDataHolder
这个类就是java中线程局部类的实现,它不同于java中的哪种实现方式,这个类完全就是包装系统的tls方面API函数,另外还提供了智能指针方面的接口
templateclass ThreadLocalDataHolder { public: //在构造的时候,调用库函数来分配一个线程局部变量的key ThreadLocalDataHolder() { _key = TlsAlloc(); } // 在析构的时候,销毁线程局部key ~ThreadLocalDataHolder() { TlsFree(_key); //这儿有个疑问,难道不用回收对应key所对应的值吗????? } // 获取当前线程所拥有的T类型的值 //返回线程所私有的T的指针,或者如果线程没有设置线程局部的话,则返回false inline T* get() const{ return (T*)TlsGetValue(_key); } // 获取当前线程的线程局部变量 //这样设计的好处是可以将ThreadLocalDataHolder看做是一个智能指针 inline T *operator->() const{ return get(); } // 返回当前线程的线程局部变量,这儿返回的是引用 inline T &operator*() const{ return *get(); } // 释放当前线程的线程局部变量 // 返回的是当前线程所有的局部变量,或者为nullptr(如果线程没有设置值的话) inline T *release() { T *result = TlsGetValue(_key); TlsSetValue(_key, nullptr); return result; } // 重新设置线程局部变量的值 //首先会先删除原来的值,然后再设置新的值 inline void reset(T *p = nullptr) { T *thing = (T*)TlsGetValue(_key); delete thing; TlsSetValue(_key, p); } private: DWORD _key;};
getThreadID函数
std::string getThreadID(){ char buf[16]; sprintf_s(buf, "%lu", ::GetCurrentThreadId()); return std::string(buf);}
就是调用系统的api函数GetCurrentThreadId()来获取当前线程标识符,因为此标识符是DWORD类型,然后调用格式化函数将 这个DWORD类型转换为字符串,并将其返回。
linux平台
- 位置:include/log4cpp/threading/PThreads.xx
Mutex
class Mutex { private: pthread_mutex_t mutex; public: inline Mutex() { ::pthread_mutex_init(&mutex, NULL); } inline void lock() { ::pthread_mutex_lock(&mutex); } inline void unlock() { ::pthread_mutex_unlock(&mutex); } inline ~Mutex() { ::pthread_mutex_destroy(&mutex); } private: Mutex(const Mutex& m); Mutex& operator=(const Mutex &m); };
ScopedLock
class ScopedLock { private: Mutex& _mutex; public: inline ScopedLock(Mutex& mutex) : _mutex(mutex) { _mutex.lock(); } inline ~ScopedLock() { _mutex.unlock(); }};
ThreadLocalDataHolder
templateclass ThreadLocalDataHolder { private: pthread_key_t _key; public: typedef T data_type; inline ThreadLocalDataHolder() { ::pthread_key_create(&_key, freeHolder); } inline static void freeHolder(void *p) { assert(p != NULL); delete reinterpret_cast (p); } inline ~ThreadLocalDataHolder() { T *data = get(); if (data != NULL) { delete data; } ::pthread_key_delete(_key); } inline T* get() const { return reinterpret_cast (::pthread_getspecific(_key)); } inline T* operator->() const { return get(); } inline T& operator*() const { return *get(); } inline T* release() { T* result = get(); ::pthread_setspecific(_key, NULL); return result; } inline void reset(T* p = NULL) { T *data = get(); if (data != NULL) { delete data; } ::pthread_setspecific(_key, p); } };
总结
threading命名空间内的一些工具类和函数,包含:
- Mutex实现的是一个平台无关的互斥量,说它平台无关是因为每一个平台都会实现自己的Mutex
- ScopedLock实现指定作用域的自动加锁、自动解锁操作
- ThreadLocalDataHolder 一个模板类,实现了线程局部类,主要注意的是,当不在使用此对象之前,必须要释放掉,存进此对象的数据。
- getThreadID 获取的是线程标识符的字符串格式。
转载地址:https://blog.csdn.net/zhizhengguan/article/details/123143548 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
初次前来,多多关照!
[***.217.46.12]2024年04月27日 02时14分11秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Java MyBatis(1)--- Generator 详解
2019-04-27
Java MyBatis(2)--- generatorConfig.xml详解与运行
2019-04-27
VueJS(5)---初步练习(5题)
2019-04-27
mysql(3)-- 修改root密码命令小结
2019-04-27
JQuery(3)--冒泡效果
2019-04-27
异常(2)-- UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/项目包名
2019-04-27
Android软键盘(1)---输入法界面管理(打开/关闭/状态获取)
2019-04-27
Android动态设置view的高度宽度
2019-04-27
css3 属性 text-overflow 实现截取多余文字内容 以省略号来代替多余内容
2019-04-27
vue 事件总线EventBus的概念、使用以及注意点
2019-04-27
JavaScript 用七种方式教你判断一个变量是否为数组类型
2019-04-27
细讲前端设置cookie, 储存用户登录信息
2019-04-27
Web前端安全策略之CSRF的攻击与防御
2019-04-27
斯坦福CS236-深度生成模型2019-全套课程资料分享
2019-04-27
知识图谱(KG)存储、可视化、公开数据集、图计算、图编程工具分享
2019-04-27
伯克利-《神经技术导论2020(带字幕)》
2019-04-27
机器学习经典书籍-《贝叶斯推理与机器学习》
2019-04-27
欧洲计算机视觉国际会议ECCR20最新论文整理分享
2019-04-27
20年6月最新-《深度神经网络的高效处理技术综述》
2019-04-27