easylogging++的那些事(四)源码分析(十四)其他工具类(三)

其他工具类二 中我们介绍了辅助性的工具类,如:通用文件操作的 File 类,通用字符串操作的 Str 类等。今天我们来看看线程安全相关类。

线程安全相关类都在 namespace el::base::threading
这里为了可移植性,考虑到 C++11 之前的和 C++11 之后所使用 API 的差异性都作了相应封装。 具体包括以下类:

  • 通用互斥量 Mutex
    • 加锁接口 lock
    • 尝试加锁接口 try_lock
    • 解锁接口 unlock
  • 通用区间锁 ScopedLock
  • 线程安全基类 ThreadSafe(仅能被继承)
    • 加锁接口: acquireLock
    • 解锁接口:releaseLock
    • 获取锁接口: lock
  • 获取当前线程 ID 通用接口(返回线程 id 的字符串): getCurrentThreadId

C++11 之后启用线程安全并且支持标准库的线程情况下,MutexScopedLock 的类型定义如下:

typedef std::recursive_mutex Mutex;
typedef std::lock_guard<base::threading::Mutex> ScopedLock;

线程安全相关类的实现如下:

namespace threading
{
#if ELPP_THREADING_ENABLED
#if !ELPP_USE_STD_THREADING
    namespace internal
    {
        /// @brief A mutex wrapper for compiler that dont yet support std::recursive_mutex
        class Mutex : base::NoCopy
        {
        public:
            Mutex(void)
            {
#if ELPP_OS_UNIX
                pthread_mutexattr_t attr;
                pthread_mutexattr_init(&attr);
                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
                pthread_mutex_init(&m_underlyingMutex, &attr);
                pthread_mutexattr_destroy(&attr);
#elif ELPP_OS_WINDOWS
                InitializeCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
            }

            virtual ~Mutex(void)
            {
#if ELPP_OS_UNIX
                pthread_mutex_destroy(&m_underlyingMutex);
#elif ELPP_OS_WINDOWS
                DeleteCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
            }

            inline void lock(void)
            {
#if ELPP_OS_UNIX
                pthread_mutex_lock(&m_underlyingMutex);
#elif ELPP_OS_WINDOWS
                EnterCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
            }

            inline bool try_lock(void)
            {
#if ELPP_OS_UNIX
                return (pthread_mutex_trylock(&m_underlyingMutex) == 0);
#elif ELPP_OS_WINDOWS
                return TryEnterCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
            }

            inline void unlock(void)
            {
#if ELPP_OS_UNIX
                pthread_mutex_unlock(&m_underlyingMutex);
#elif ELPP_OS_WINDOWS
                LeaveCriticalSection(&m_underlyingMutex);
#endif // ELPP_OS_UNIX
            }

        private:
#if ELPP_OS_UNIX
            pthread_mutex_t m_underlyingMutex;
#elif ELPP_OS_WINDOWS
            CRITICAL_SECTION m_underlyingMutex;
#endif // ELPP_OS_UNIX
        };
        /// @brief Scoped lock for compiler that dont yet support std::lock_guard
        template <typename M>
        class ScopedLock : base::NoCopy
        {
        public:
            explicit ScopedLock(M &mutex)
            {
                m_mutex = &mutex;
                m_mutex->lock();
            }

            virtual ~ScopedLock(void)
            {
                m_mutex->unlock();
            }

        private:
            M *m_mutex;
            ScopedLock(void);
        };
    } // namespace internal
    typedef base::threading::internal::Mutex Mutex;
    typedef base::threading::internal::ScopedLock<base::threading::Mutex> ScopedLock;
#else
    typedef std::recursive_mutex Mutex;
    typedef std::lock_guard<base::threading::Mutex> ScopedLock;
#endif // !ELPP_USE_STD_THREADING
#else
    namespace internal
    {
        /// @brief Mutex wrapper used when multi-threading is disabled.
        class NoMutex : base::NoCopy
        {
        public:
            NoMutex(void) {}
            inline void lock(void) {}
            inline bool try_lock(void)
            {
                return true;
            }
            inline void unlock(void) {}
        };
        /// @brief Lock guard wrapper used when multi-threading is disabled.
        template <typename Mutex>
        class NoScopedLock : base::NoCopy
        {
        public:
            explicit NoScopedLock(Mutex &)
            {
            }
            virtual ~NoScopedLock(void)
            {
            }

        private:
            NoScopedLock(void);
        };
    } // namespace internal
    typedef base::threading::internal::NoMutex Mutex;
    typedef base::threading::internal::NoScopedLock<base::threading::Mutex> ScopedLock;
#endif // ELPP_THREADING_ENABLED
    /// @brief Base of thread safe class, this class is inheritable-only
    class ThreadSafe
    {
    public:
        virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); }
        virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); }
        virtual inline base::threading::Mutex &lock(void) ELPP_FINAL { return m_mutex; }

    protected:
        ThreadSafe(void) {}
        virtual ~ThreadSafe(void) {}

    private:
        base::threading::Mutex m_mutex;
    };

#if ELPP_THREADING_ENABLED
#if !ELPP_USE_STD_THREADING
    /// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned.
    static std::string getCurrentThreadId(void)
    {
        std::stringstream ss;
#if (ELPP_OS_WINDOWS)
        ss << GetCurrentThreadId();
#endif // (ELPP_OS_WINDOWS)
        return ss.str();
    }
#else
    /// @brief Gets ID of currently running threading using std::this_thread::get_id()
    static std::string getCurrentThreadId(void)
    {
        std::stringstream ss;
        ss << std::this_thread::get_id();
        return ss.str();
    }
#endif // !ELPP_USE_STD_THREADING
#else
    static inline std::string getCurrentThreadId(void)
    {
        return std::string();
    }
#endif // ELPP_THREADING_ENABLED
} // namespace threading

上面的代码考虑到未启用线程安全,跨平台和系统不支持标准库线程的情况,出现了很多条件编译分支,代码本身并不复杂。

线程安全相关类到这里就介绍完了。至此,easylogging++的源码就差不多分析完了,剩下的一些类模板的源码我会在后面的设计理念篇逐一介绍。

posted @ 2022-12-09 23:48  节奏自由  阅读(57)  评论(0编辑  收藏  举报