【C++模块实现】| 【01】日志系统实现
【C++模块实现】| 【02】日志系统优化
【C++模块实现】| 【03】文件管理模块
【C++模块实现】| 【04】配置模块
【C++模块实现】| 【05】日志模块增加配置模块的功能
【C++模块实现】| 【06】日志模块添加循环覆盖写文件功能
该模块是从sylar服务器框架中学习的,以下将会对其进行总结以加深对该框架的理解;
========》互斥量、信号量、条件变量的基本使用及参考代码《=======
以下对锁的封装能够使用类的构造函数来加锁,析构函数进行释放锁;
sylar::Mutex s_mutes;
{
sylar::Mutex::Lock lock(s_mutes); // 加锁操作
...
// 当离开该作用域时,该lock会被回收,由于它时自动变量,此时即调用析构函数,执行是方法锁的操作;
// 该方法简化了锁的使用方法,不需要手动释放锁,避免出现死锁的现象;
}
互斥锁Mutex是一种用于多线程编程中,防止两条线程同时对同一公共资源进行读写的机制;
- 该目的通过将代码切片成一个一个的临界区域(critical section)达成;
- 临界区域指的是一块对公共资源进行存取的代码,并非一种机制或是算法;
- 一个程序、进程、线程可以拥有多个临界区域,但是并不一定会应用互斥锁。
flag、队列、计数器、中断处理程序等用于在多条并行运行的代码间传递数据、同步状态等的资源。维护这些资源的同步、一致和完
整是很困难的,因为一条线程可能在任何一个时刻被暂停(休眠)或者恢复(唤醒);
// 声明一个互斥量
pthread_mutex_t mtx;
// 初始化
pthread_mutex_init(&mtx, NULL);
// 加锁
pthread_mutex_lock(&mtx);
// 解锁
pthread_mutex_unlock(&mtx);
// 销毁
pthread_mutex_destroy(&mtx);
/**
* @brief 互斥量
*/
class Mutex : Noncopyable {
public:
/// 局部锁
typedef ScopedLockImpl<Mutex> Lock;
/**
* @brief 构造函数
*/
Mutex() {
pthread_mutex_init(&m_mutex, nullptr);
}
/**
* @brief 析构函数
*/
~Mutex() {
pthread_mutex_destroy(&m_mutex);
}
/**
* @brief 加锁
*/
void lock() {
pthread_mutex_lock(&m_mutex);
}
/**
* @brief 解锁
*/
void unlock() {
pthread_mutex_unlock(&m_mutex);
}
pthread_mutex_t getMutex() const { return m_mutex; }
private:
/// mutex
pthread_mutex_t m_mutex;
};
读写锁是计算机程序的并发控制的一种同步机制,用于解决读写问题。读操作可并发重入,写操作是互斥的;
- 读写锁通常用互斥锁、条件变量、信号量实现;
【读写锁可以有不同的操作模式优先级】
- 读操作优先:允许最大并发,但写操作可能饿死;
- 写操作优先:一旦所有已经开始的读操作完成,等待的写操作立即获得锁。内部实现需要两把互斥锁;
- 未指定优先级
/**
* @brief 读写互斥量
*/
class RWMutex : Noncopyable{
public:
/// 局部读锁
typedef ReadScopedLockImpl<RWMutex> ReadLock;
/// 局部写锁
typedef WriteScopedLockImpl<RWMutex> WriteLock;
/**
* @brief 构造函数
*/
RWMutex() {
pthread_rwlock_init(&m_lock, nullptr);
}
/**
* @brief 析构函数
*/
~RWMutex() {
pthread_rwlock_destroy(&m_lock);
}
/**
* @brief 上读锁
*/
void rdlock() {
pthread_rwlock_rdlock(&m_lock);
}
/**
* @brief 上写锁
*/
void wrlock() {
pthread_rwlock_wrlock(&m_lock);
}
/**
* @brief 解锁
*/
void unlock() {
pthread_rwlock_unlock(&m_lock);
}
private:
/// 读写锁
pthread_rwlock_t m_lock;
};
自旋锁是计算机科学用于多线程同步的一种锁,线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等
待。一旦获取了自旋锁,线程会一直保持该锁,直至显式释放自旋锁;
- 自旋锁避免了进程上下文的调度开销,因此对于线程只会阻塞很短时间的场合是有效的;
- 自旋锁用于处理器之间的互斥,适合保护很短的临界区,并且不允许在临界区睡眠。申请自旋锁的时候,如果自旋锁被其他处理器
占有,本处理器自旋等待(也称为忙等待);因此操作系统的实现在很多地方往往用自旋锁;
- 单核CPU不适于使用自旋锁,这里的单核CPU指的是单核单线程的CPU,因为,在同一时间只有一个线程是处在运行状态,假设
运行线程A发现无法获取锁,只能等待解锁,但因为A自身不挂起,所以那个持有锁的线程B没有办法进入运行状态,只能等到操
作系统分给A的时间片用完,才能有机会被调度。这种情况下使用自旋锁的代价很高;
获取、释放自旋锁,实际上是读写自旋锁的存储内存或寄存器。因此这种读写操作必须是原子的;
通常用test-and-set等原子操作来实现;
【优点】:
- 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上
下文切换,执行速度快。
- 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。
(线程被阻塞后便进入内核(Linux)调度状态,这个会导致系统在用户态与内核态之间来回切换,严重影响锁的性能)。
/**
* @brief 自旋锁
*/
class Spinlock : Noncopyable {
public:
/// 局部锁
typedef ScopedLockImpl<Spinlock> Lock;
/**
* @brief 构造函数
*/
Spinlock() {
pthread_spin_init(&m_mutex, 0);
}
/**
* @brief 析构函数
*/
~Spinlock() {
pthread_spin_destroy(&m_mutex);
}
/**
* @brief 上锁
*/
void lock() {
pthread_spin_lock(&m_mutex);
}
/**
* @brief 解锁
*/
void unlock() {
pthread_spin_unlock(&m_mutex);
}
private:
/// 自旋锁
pthread_spinlock_t m_mutex;
};
/**
* @brief 局部锁的模板实现
*/
template<class T>
struct ScopedLockImpl {
public:
/**
* @brief 构造函数
* @param[in] mutex Mutex
*/
ScopedLockImpl(T& mutex)
:m_mutex(mutex) {
m_mutex.lock();
m_locked = true;
}
/**
* @brief 析构函数,自动释放锁
*/
~ScopedLockImpl() {
unlock();
}
/**
* @brief 加锁
*/
void lock() {
if(!m_locked) {
m_mutex.lock();
m_locked = true;
}
}
/**
* @brief 解锁
*/
void unlock() {
if(m_locked) {
m_mutex.unlock();
m_locked = false;
}
}
private:
/// mutex
T& m_mutex;
/// 是否已上锁
bool m_locked;
};
/**
* @brief 局部读锁模板实现
*/
template<class T>
struct ReadScopedLockImpl {
public:
/**
* @brief 构造函数
* @param[in] mutex 读写锁
*/
ReadScopedLockImpl(T& mutex)
:m_mutex(mutex) {
m_mutex.rdlock();
m_locked = true;
}
/**
* @brief 析构函数,自动释放锁
*/
~ReadScopedLockImpl() {
unlock();
}
/**
* @brief 上读锁
*/
void lock() {
if(!m_locked) {
m_mutex.rdlock();
m_locked = true;
}
}
/**
* @brief 释放锁
*/
void unlock() {
if(m_locked) {
m_mutex.unlock();
m_locked = false;
}
}
private:
/// mutex
T& m_mutex;
/// 是否已上锁
bool m_locked;
};
/**
* @brief 局部写锁模板实现
*/
template<class T>
struct WriteScopedLockImpl {
public:
/**
* @brief 构造函数
* @param[in] mutex 读写锁
*/
WriteScopedLockImpl(T& mutex)
:m_mutex(mutex) {
m_mutex.wrlock();
m_locked = true;
}
/**
* @brief 析构函数
*/
~WriteScopedLockImpl() {
unlock();
}
/**
* @brief 上写锁
*/
void lock() {
if(!m_locked) {
m_mutex.wrlock();
m_locked = true;
}
}
/**
* @brief 解锁
*/
void unlock() {
if(m_locked) {
m_mutex.unlock();
m_locked = false;
}
}
private:
/// Mutex
T& m_mutex;
/// 是否已上锁
bool m_locked;
};
========》使用互斥锁及条件变量替代信号量《========
/**
* @brief 信号量
*/
class Semaphore : Noncopyable {
public:
/**
* @brief 构造函数
* @param[in] count 信号量值的大小
*/
Semaphore(uint32_t count = 0);
/**
* @brief 析构函数
*/
~Semaphore();
/**
* @brief 获取信号量
*/
void wait();
/**
* @brief 释放信号量
*/
void notify();
private:
sem_t m_semaphore;
};
/** 信号量封装使用条件变量和锁 */
class OwnSemaphore : Noncopyable {
public:
typedef Mutex MutexType;
OwnSemaphore(size_t count=0);
~OwnSemaphore();
void wait();
void notify();
size_t getCount() const { return m_count; }
void reset() { m_count = 0;}
private:
size_t m_count;
MutexType m_mutex;
Cond m_cond;
};
Semaphore::Semaphore(uint32_t count) {
if(sem_init(&m_semaphore, 0, count)) {
throw std::logic_error("sem_init error");
}
}
Semaphore::~Semaphore() {
sem_destroy(&m_semaphore);
}
void Semaphore::wait() {
if(sem_wait(&m_semaphore)) {
throw std::logic_error("sem_wait error");
}
}
void Semaphore::notify() {
if(sem_post(&m_semaphore)) {
throw std::logic_error("sem_post error");
}
}
OwnSemaphore::OwnSemaphore(size_t count)
:m_count(count){
}
OwnSemaphore::~OwnSemaphore() {
}
void OwnSemaphore::wait() {
MutexType::Lock lock(m_mutex);
while (m_count == 0) {
m_cond.wait(m_mutex.getMutex());
}
--m_count;
}
void OwnSemaphore::notify() {
m_count++;
m_cond.signal();
}
/** 封装条件变量 */
class Cond {
public:
Cond();
void wait(pthread_mutex_t mutex);
void signal();
~Cond();
private:
pthread_cond_t m_cond;
};
Cond::Cond() {
pthread_cond_init(&m_cond, NULL);
}
void Cond::wait(pthread_mutex_t mutex) {
pthread_cond_wait(&m_cond, &mutex);
}
void Cond::signal() {
pthread_cond_signal(&m_cond);
}
Cond::~Cond() {
pthread_cond_destroy(&m_cond);
}
/**
* @brief 原子锁
*/
class CASLock : Noncopyable {
public:
/// 局部锁
typedef ScopedLockImpl<CASLock> Lock;
/**
* @brief 构造函数
*/
CASLock() {
m_mutex.clear();
}
/**
* @brief 析构函数
*/
~CASLock() {
}
/**
* @brief 上锁
*/
void lock() {
while(std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire));
}
/**
* @brief 解锁
*/
void unlock() {
std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
}
private:
/// 原子状态
volatile std::atomic_flag m_mutex;
};