> 文章列表 > c++积累5-lock_guard使用

c++积累5-lock_guard使用

c++积累5-lock_guard使用

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;
}

输出:
c++积累5-lock_guard使用
可以看到,结果并不是我们所期望的,那么我们使用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;
}

输出:
c++积累5-lock_guard使用
我们可以看到加了锁之后呢,输出结果是正确的了

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;
}

输出:
c++积累5-lock_guard使用
可以看到这里的输出也是正确的。

std::lock_guard原理跟这个也是一样的,我们看下它的源码:
c++积累5-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;
}

输出:
c++积累5-lock_guard使用
看结果也是正确的。

总结三个代码在例子中的不同处:
c++积累5-lock_guard使用
c++积累5-lock_guard使用
c++积累5-lock_guard使用