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函数,另外还提供了智能指针方面的接口

template 
class 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

template
class 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:log4cpp源码阅读:StringUtil工具类
下一篇:log4cpp源码阅读:NDC类学习

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月27日 02时14分11秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章