1、std:mutex
在了解lock_guard之前,需要先学习下std:mutex,因为lock_guard内部就是使用的std:mutex
std:mutex:是一个用于保护共享数据不会同时被多个线程访问的类,它叫做互斥量。我们可以把它看作一把锁,基本使用如下:
#include <mutex>
std::mutex kMutex;
void function() {
//加锁
kMutex.lock();
//kMutex.try_lock();
//do something that is thread safe...
// 离开作用域解锁
kMutex.unlock();
}
来看一个例子,两个线程共同访问一个全局变量
首先我们实现一个不加锁的看看有什么问题:
#include <iostream>
#include <thread>
int gData = 0;
std::mutex kMutex;
void increment(){
for (int i = 0; i < 1000000; i++) {
gData++;
std::cout<< std::this_thread::get_id() << ":"<< gData << std::endl;
}
}
int main() {
std::cout<< __FUNCTION__ << ":" << gData << std::endl;
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
getchar();
return 0;
}
输出:
可以看到,结果并不是我们所期望的,那么我们使用mutex加上锁之后看下:
#include <iostream>
#include <thread>
int gData = 0;
std::mutex kMutex;
void increment(){
kMutex.lock();
for (int i = 0; i < 1000000; i++) {
gData++;
std::cout<< std::this_thread::get_id() << ":"<< gData << std::endl;
}
kMutex.unlock();
}
int main() {
std::cout<< __FUNCTION__ << ":" << gData << std::endl;
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
getchar();
return 0;
}
输出:
我们可以看到加了锁之后呢,输出结果是正确的了
2、std:lock_guard
std:lock_guard 其实就是对std:mutex的一个包装类,能够实现自动unlock,而不必手动进行unlock操作。它在构造中完成加锁,在析构中完成解锁。
先让我们自己实现一个这样的类:
namespace myspace{
template<typename T> class my_lock_guard{
public:
my_lock_guard(T& mutex):mutex_(mutex){
// 构造加锁
mutex_.lock();
}
~my_lock_guard(){
// 析构解锁
mutex_.unlock();
}
private:
// 不可赋值,不可拷贝
my_lock_guard(my_lock_guard const&);
my_lock_guard& operator=(my_lock_guard const&);
private:
T& mutex_;
};
}
还是按照上面小节中的例子:
#include <iostream>
#include <thread>
int gData = 0;
std::mutex kMutex;
namespace myspace{
template<typename T> class my_lock_guard{
public:
my_lock_guard(T& mutex):mutex_(mutex){
// 构造加锁
mutex_.lock();
}
~my_lock_guard(){
// 析构解锁
mutex_.unlock();
}
private:
// 不可赋值,不可拷贝
my_lock_guard(my_lock_guard const&);
my_lock_guard& operator=(my_lock_guard const&);
private:
T& mutex_;
};
}
void increment(){
myspace::my_lock_guard<std::mutex> myLockGuard(kMutex);
for (int i = 0; i < 1000000; i++) {
gData++;
std::cout<< std::this_thread::get_id() << ":"<< gData << std::endl;
}
}
int main() {
std::cout<< __FUNCTION__ << ":" << gData << std::endl;
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
getchar();
return 0;
}
输出:
可以看到这里的输出也是正确的。
std::lock_guard原理跟这个也是一样的,我们看下它的源码:
例子代码:
#include <iostream>
#include <thread>
int gData = 0;
std::mutex kMutex;
namespace myspace{
template<typename T> class my_lock_guard{
public:
my_lock_guard(T& mutex):mutex_(mutex){
// 构造加锁
mutex_.lock();
}
~my_lock_guard(){
// 析构解锁
mutex_.unlock();
}
private:
// 不可赋值,不可拷贝
my_lock_guard(my_lock_guard const&);
my_lock_guard& operator=(my_lock_guard const&);
private:
T& mutex_;
};
}
void increment(){
std::lock_guard<std::mutex> lockGuard(kMutex);
for (int i = 0; i < 1000000; i++) {
gData++;
std::cout<< std::this_thread::get_id() << ":"<< gData << std::endl;
}
}
int main() {
std::cout<< __FUNCTION__ << ":" << gData << std::endl;
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
getchar();
return 0;
}
输出:
看结果也是正确的。
总结三个代码在例子中的不同处: