0
点赞
收藏
分享

微信扫一扫

log4cpp源码阅读:threading工具类

A邱凌 2022-02-26 阅读 81

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<Appender*> _appenders;
};

这样实现可以保证对_appenders的访问是线程安全的

ThreadLocalDataHolder

这个类就是java中线程局部类的实现,它不同于java中的哪种实现方式,这个类完全就是包装系统的tls方面API函数,另外还提供了智能指针方面的接口

template <typename T>
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<typename T> 
 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<T *>(p);
             }

            inline ~ThreadLocalDataHolder() {
                T *data = get();
                if (data != NULL) { 
                    delete data;
                }
                ::pthread_key_delete(_key);
            }
            
            inline T* get() const {
                return reinterpret_cast<T *>(::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 获取的是线程标识符的字符串格式。
举报

相关推荐

0 条评论