threading namespace
- Location: in the include/log4cpp/threading directory
- The corresponding classes are under the threading namespace. This namespace contains some thread synchronization classes and methods to get the current thread. There is also an implementation of thread scoped local variables
- Because thread is a system kernel object, and different compiler platforms also encapsulate the excuse of thread differently, it has many implementations, that is, the names of specific implementation classes on different platforms may be different. Different are masked here, and the same name is provided: Mutex, ScopedLock, ThreadLocalDataHolder, getThreadID
win platform
- Location: Include / log4cpp / threading / msthreads xx
Mutex class
- Function: this class implements the function of mutex, which can be used to protect some access and is thread safe. Let's take a look at his code implementation on win32 platform.
class MSMutex { public: //Create a critical area object in the constructor MSMutex() { InitializeCriticalSection(&_criticalSection); } // Destroy critical area objects in destructor ~MSMutex() { DeleteCriticalSection(&_criticalSection); } // Returns the critical area object of the wrapper inline LPCRITICAL_SECTION getCriticalSection() { return &_criticalSection; } private: //Copy is prohibited, otherwise deadlock is likely to occur (because the operation is inconsistent) MSMutex(const MSMutex&); CRITICAL_SECTION _criticalSection; //Critical zone object }; typedef MSMutex Mutex; // A simple non recursive lock
It can be seen that Mutex is an alias of MSMutex. The implementation of MSMutex actually wraps a critical area object. The object is created when the object is constructed and destroyed when the object is destructed. It also provides an interface for users to access, getCriticalSection method, and finally defines two private methods to prohibit the object from being copied
ScopedLock class
//A scope local lock class MSScopedLock { public: //Enter lock in constructor MSScopedLock(MSMutex &mutex) { _criticalSection = mutex.getCriticalSection(); EnterCriticalSection(_criticalSection); } // Release lock in destructor ~MSScopedLock() { LeaveCriticalSection(_criticalSection); } private: MSScopedLock(const MSScopedLock& other); // Binary object is copied LPCRITICAL_SECTION _criticalSection; // Internally saved critical area object pointer }; typedef MSScopedLock ScopedLock; // Here is the unified name type of ScopedLock defined
You can see that the real type of ScopedLock is MSCopedLock. The logic is very simple. You must use the Mutex object to construct and then enter the critical area object. Then, when the ScopedLock object is destructed again, leave the critical area, which can ensure that the methods in a scope are safe. such as
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; };
This implementation can ensure that_ appenders access is thread safe
ThreadLocalDataHolder
This class is the implementation of the thread local class in java. It is different from the implementation method in java. This class is completely the tls API function of the packaging system. In addition, it also provides the interface of intelligent pointer
template <typename T> class ThreadLocalDataHolder { public: //When constructing, call the library function to allocate the key of a thread local variable ThreadLocalDataHolder() { _key = TlsAlloc(); } // When destructing, destroy the local key of the thread ~ThreadLocalDataHolder() { TlsFree(_key); //Here's a question. Don't you recycle the value corresponding to the corresponding key????? } // Gets the value of the T type owned by the current thread //Returns the pointer to T that is private to the thread, or false if the thread does not have a thread local set inline T* get() const{ return (T*)TlsGetValue(_key); } // Gets the thread local variable of the current thread //The advantage of this design is that ThreadLocalDataHolder can be regarded as a smart pointer inline T *operator->() const{ return get(); } // Returns the thread local variable of the current thread, where the reference is returned inline T &operator*() const{ return *get(); } // Thread's current local variable release // Returns all local variables of the current thread, or nullptr (if the thread has no value set) inline T *release() { T *result = TlsGetValue(_key); TlsSetValue(_key, nullptr); return result; } // Reset the value of the thread local variable //First, the original value will be deleted, and then the new value will be set inline void reset(T *p = nullptr) { T *thing = (T*)TlsGetValue(_key); delete thing; TlsSetValue(_key, p); } private: DWORD _key; };
getThreadID function
std::string getThreadID() { char buf[16]; sprintf_s(buf, "%lu", ::GetCurrentThreadId()); return std::string(buf); }
That is to call the api function GetCurrentThreadId() of the system to get the current thread identifier, because the identifier is DWORD type, and then call the formatting function to convert the DWORD type into a string and return it.
linux platform
- Location: 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); } };
summary
Some tool classes and functions in threading namespace, including:
- Mutex implements a platform independent mutex, which is said to be platform independent because each platform will implement its own mutex
- ScopedLock implements the automatic locking and unlocking of the specified scope
- ThreadLocalDataHolder is a template class that implements the thread local class. The main thing to note is that when this object is not used, it must be released and the data stored in this object.
- getThreadID gets the string format of the thread identifier.