1. ScopedLockImpl三个规范接口

用于规范结构,内部保存锁引用对象,该规范可以自动完成作用域内的加锁和解锁,构造函数自动完成加锁,在作用域内实例化ScopedLockImpl并传入一个已经实例化的锁对象,在构造函数完成加锁,在作用域结束后,被自动销毁,并调用析构函数完成解锁。全过程自动,非常好用👍

  • 成员变量T& m_mutex:保存锁引用对象
  • 成员变量bool m_locked:记录是否上锁
  • 成员函数全部为lock()unlock(),但读写类型的锁在内部调用的是锁引用对象的rdlock()wrlock()unlock()

1.1 ScopedLockImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template<class T>
struct ScopedLockImpl {
public:
ScopedLockImpl(T& mutex)
:m_mutex(mutex) {
m_mutex.lock();
m_locked = true;
}
~ScopedLockImpl() {
unlock();
}

void lock() {
if (!m_locked) {
m_mutex.lock();
m_locked = true;
}
}

void unlock() {
if (m_locked) {
m_mutex.unlock();
m_locked = false;
}
}
private:
T& m_mutex;
bool m_locked;
};

1.2 ReadScopedLockImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template<class T>
struct ReadScopedLockImpl {
public:
ReadScopedLockImpl(T& mutex)
:m_mutex(mutex) {
m_mutex.rdlock();
m_locked = true;
}
~ReadScopedLockImpl() {
unlock();
}

void lock() {
if (!m_locked) {
m_mutex.rdlock();
m_locked = true;
}
}

void unlock() {
if (m_locked) {
m_mutex.unlock();
m_locked = false;
}
}
private:
T& m_mutex;
bool m_locked;
};

1.3 ScopedLockImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template<class T>
struct WriteScopedLockImpl {
public:
WriteScopedLockImpl(T& mutex)
:m_mutex(mutex) {
m_mutex.wrlock();
m_locked = true;
}
~WriteScopedLockImpl() {
unlock();
}

void lock() {
if (!m_locked) {
m_mutex.wrlock();
m_locked = true;
}
}

void unlock() {
if (m_locked) {
m_mutex.unlock();
m_locked = false;
}
}
private:
T& m_mutex;
bool m_locked;
};

2. 锁

2.1 Semaphore

信号量,保存一个非负整数

  • 成员变量sem_t:记录信号量的值
  • 成员函数wait():使信号量增加
  • 成员函数notify():使信号量减少
  • 构造函数完成信号量的初始化,析构函数完成信号量的销毁
1
2
3
4
5
6
7
8
9
10
11
12
13
class Semaphore {
public:
Semaphore(uint32_t count = 0);
~Semaphore();
void wait();
void notify();
private:
Semaphore(const Semaphore&) = delete;
Semaphore(const Semaphore&&) = delete;
Semaphore& operator=(const Semaphore&) = delete;
private:
sem_t m_semaphore;
};

2.2 Mutex

最简单的互斥锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Mutex {
public:
typedef ScopedLockImpl<Mutex> Lock;
Mutex() {
pthread_mutex_init(&m_mutex, nullptr);
}
~Mutex() {
pthread_mutex_destroy(&m_mutex);
}
void lock() {
pthread_mutex_lock(&m_mutex);
}
void unlock() {
pthread_mutex_unlock(&m_mutex);
}
private:
pthread_mutex_t m_mutex;
};

2.3 rwlock

读写锁内部有两个typedef关键字,定义了ReadLockWriteLock两个类型,提供了简单的读写锁作用域自动加锁解锁的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class RWMutex {
public:
typedef ReadScopedLockImpl<RWMutex> ReadLock;
typedef WriteScopedLockImpl<RWMutex> WriteLock;
RWMutex() {
pthread_rwlock_init(&m_lock, nullptr);
}
~RWMutex() {
pthread_rwlock_destroy(&m_lock);
}
void rdlock() {
pthread_rwlock_rdlock(&m_lock);
}
void wrlock() {
pthread_rwlock_wrlock(&m_lock);
}
void unlock() {
pthread_rwlock_unlock(&m_lock);
}

private:
pthread_rwlock_t m_lock;
};

2.4 Spinlock

自旋锁,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,避免一睡眠就被调度,降低性能。对于IO等待很长的适合用互斥,但是就等一瞬间的还是自旋效率高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Spinlock {
public:
typedef ScopedLockImpl<Spinlock> Lock;
Spinlock() {
pthread_spin_init(&m_mutex, 0);
}
~Spinlock() {
pthread_spin_destroy(&m_mutex);
}
void lock() {
pthread_spin_lock(&m_mutex);
}
void unlock() {
pthread_spin_unlock(&m_mutex);
}
private:
pthread_spinlock_t m_mutex;
};

2.5 CASLock

原子操作改变atomic_flag m_mutex,同样获得锁的时候自旋

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CASLock {
public:
typedef ScopedLockImpl<CASLock> Lock;
CASLock() {
m_mutex.clear();
}
~CASLock() {
}
void lock() {
while (std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire));
}
void unlock() {
std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
}
private:
volatile std::atomic_flag m_mutex;
};

3. 使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sylar::RWMutex s_mutex;
int pthread = 0;
// 多线程调用该函数时,pthread大概率小于线程数量*10000,通过加锁可以保证得到正确结果
void thread_fun() {
for (int i = 0; i < 1000000; ++i) {
// 创建一个WriteScopedLockImpl<RWMutex>对象,传入s_mutex锁
// 构造函数自动加锁
sylar::RWMutex::WriteLock lock(s_mutex);
++pthread;
// 离开作用域调用析构函数自动解锁
}
}

int main()
{
std::thread thread1(thread_fun);
std::thread thread2(thread_fun);
thread1.join();
thread2.join();
std::cout<<pthread<<std::endl; // 加锁后应该得到正确结果2000000
}