1.RAll机制
RAII 是 resource acquisition is initialization 的缩写,意为“资源获取即初始化”。它是 C++ 之父 Bjarne Stroustrup 提出的设计理念,其核心是把资源和对象的生命周期绑定,对象创建获取资源,对象销毁释放资源。在 RAII 的指导下,C++ 把底层的资源管理问题提升到了对象生命周期管理的更高层次。
2.RAll机制的线程锁实现
2.1MutexLockGuard.h
#include <pthread.h>
#include <iostream>
using namespace std;
class MutexLockGuard {
public:
explicit MutexLockGuard();
~MutexLockGuard();
private:
static pthread_mutex_t qlock;
private:
MutexLockGuard(const MutexLockGuard &);
MutexLockGuard &operator=(const MutexLockGuard &);
};
2.2MutexLockGuard.cpp
#include "MutexLockGuard.h"
MutexLockGuard::MutexLockGuard() {
pthread_mutex_lock(&this->qlock);
cout << "Constructor MutexLockGuard" << endl;
}
MutexLockGuard::~MutexLockGuard() {
pthread_mutex_unlock(&this->qlock);
cout << " Destructor MutexLockGuard" << endl;
}
2.3 在main.cpp中使用
2.3.1 形式一,局部对象
局部对象会在出作用域的时候在调用析构函数。因此在进行线程同步的时候可以采用局部变量的形式,而main()中,MutexLockGuard aa的作用域为以下部分,大括号之间的部分,也可以称为“锁的粒度”。
{
MutexLockGuard aa; /* 形式1*/
cout << "hello world1" << endl;
a = a + 1;
cout << "hello world2" << endl;
}/* MutexLockGuard在离开此处时被析构 */
#include <iostream>
#include "MutexLockGuard.h"
using namespace std;
/*初始化MutexLockGuard中的静态成员变量qlock*/
pthread_mutex_t MutexLockGuard::qlock = PTHREAD_MUTEX_INITIALIZER;
int a = 0;
{
MutexLockGuard aa; /* 形式1*/
cout << "hello world1" << endl;
a = a + 1;
cout << "hello world2" << endl;
}/* MutexLockGuard在离开此处时被析构 */
cout << "hello world3" << endl;
cout << "a = " << a << endl;
return 0;
运行结果:
Constructor MutexLockGuard
hello world1
hello world2
Destructor MutexLockGuard
hello world3
a = 1
2.3.2 形式2,临时对象
没有名字的对象就是临时对象,它存在于完整的表达式的生存其间,就是说,当表达式计算结束后就会被释放。当“MutexLockGuard();"该句运行结束后,会自动调用析构函数。
int main() {
int a = 0;
{
MutexLockGuard(); /* 形式2*/
cout << "hello world1" << endl;
a = a + 1;
cout << "hello world2" << endl;
}
cout << "hello world3" << endl;
cout << "a = " << a << endl;
return 0;
}
运行结果:
Constructor MutexLockGuard
Destructor MutexLockGuard
hello world1
hello world2
hello world3
a = 1
3.RAll机制的思路
个人理解,主要有以下几个关键点:
- qlock声明为static类型
声明为static确保了全局只有一个qlock,无论创建多少MutexLockGuard对象,qlock都是同一个,既然是共用,则只要一个对象的qlock->lock后,那么其他对象必须等到qlock->unlock之后,才能继续lock,从而实现了互斥锁,这是利用了static成员变量共享的特点。 - 构造函数 lock
在构造函数中lock,那么一旦创建对象,就可以自动实现lock。 - 析构函数unlock
在析构函数中unlock,那么一旦对象被自动释放(即对象出了作用域后),就可以自动实现unlock。 - 用声明周期控制锁的粒度
通过{ }实现对对象生命周期的控制,在大括号内声明对象,当对象离开大括号,则自动调用析构函数,从而实现自动解锁,而大括号也就是锁的粒度。
4.备注
(1)例如,如下形式会被阻,因为aa1没有被析构,即锁没有被unlock,所以无法构建aa2。
{
MutexLockGuard aa1;
cout << "hello world0" << endl;
MutexLockGuard aa2;
cout << "hello world1" << endl;
a = a + 1;
cout << "hello world2" << endl;
}
运行输出:
Constructor MutexLockGuard
hello world0
(2)不要用new来创建对象,因为使用了堆中的空间,需要手动释放或者使用其他方式进行释放。