C++ 并发编程,std::unique_lock与std::lock_guard区别示例

背景

平时看代码时,也会使用到std::lock_guard,可是std::unique_lock用的比较少。在看并发编程,这里总结一下。方便后续使用。ios

std::unique_lock也能够提供自动加锁、解锁功能,比std::lock_guard更加灵活。c++

std::lock_guard

std::lock_guard是RAII模板类的简单实现,功能简单。编程

1.std::lock_guard 在构造函数中进行加锁,析构函数中进行解锁。
2.锁在多线程编程中,使用较多,所以c++11提供了lock_guard模板类;在实际编程中,咱们也能够根据本身的场景编写resource_guard RAII类,避免忘掉释放资源。markdown

下面是一个使用std::lock_guard的代码例子,1+2+ .. + 100的多线程实现,每一个num只能由一个线程处理。:多线程

#include <thread> #include <mutex> #include <vector> #include <iostream> #include <algorithm> std::mutex my_lock; void add(int &num, int &sum){ while(true){ std::lock_guard<std::mutex> lock(my_lock); if (num < 100){ //运行条件 num += 1; sum += num; } else { //退出条件 break; } } } int main(){ int sum = 0; int num = 0; std::vector<std::thread> ver; //保存线程的vector for(int i = 0; i < 20; ++i){ std::thread t = std::thread(add, std::ref(num), std::ref(sum)); ver.emplace_back(std::move(t)); //保存线程 } std::for_each(ver.begin(), ver.end(), std::mem_fn(&std::thread::join)); //join std::cout << sum << std::endl; }#include <thread> #include <mutex> #include <vector> #include <iostream> #include <algorithm> std::mutex my_lock; void add(int &num, int &sum){ while(true){ std::lock_guard<std::mutex> lock(my_lock); if (num < 100){ //运行条件 num += 1; sum += num; } else { //退出条件 break; } } } int main(){ int sum = 0; int num = 0; std::vector<std::thread> ver; //保存线程的vector for(int i = 0; i < 20; ++i){ std::thread t = std::thread(add, std::ref(num), std::ref(sum)); ver.emplace_back(std::move(t)); //保存线程 } std::for_each(ver.begin(), ver.end(), std::mem_fn(&std::thread::join)); //join std::cout << sum << std::endl; }

std::unique_lock

类 unique_lock 是通用互斥包装器,容许延迟锁定、锁定的有时限尝试、递归锁定、全部权转移和与条件变量一同使用
unique_lock比lock_guard使用更加灵活,功能更增强大。
使用unique_lock须要付出更多的时间、性能成本。并发

下面是try_lock的使用例子。函数

#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock #include <vector> std::mutex mtx; // mutex for critical section std::once_flag flag; void print_block (int n, char c) { //unique_lock有多组构造函数, 这里std::defer_lock不设置锁状态 std::unique_lock<std::mutex> my_lock (mtx, std::defer_lock); //尝试加锁, 若是加锁成功则执行 //(适合定时执行一个job的场景, 一个线程执行就能够, 能够用更新时间戳辅助) if(my_lock.try_lock()){ for (int i=0; i<n; ++i) std::cout << c; std::cout << '\n'; } } void run_one(int &n){ std::call_once(flag, [&n]{n=n+1;}); //只执行一次, 适合延迟加载; 多线程static变量状况 } int main () { std::vector<std::thread> ver; int num = 0; for (auto i = 0; i < 10; ++i){ ver.emplace_back(print_block,50,'*'); ver.emplace_back(run_one, std::ref(num)); } for (auto &t : ver){ t.join(); } std::cout << num << std::endl; return 0; }#include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock #include <vector> std::mutex mtx; // mutex for critical section std::once_flag flag; void print_block (int n, char c) { //unique_lock有多组构造函数, 这里std::defer_lock不设置锁状态 std::unique_lock<std::mutex> my_lock (mtx, std::defer_lock); //尝试加锁, 若是加锁成功则执行 //(适合定时执行一个job的场景, 一个线程执行就能够, 能够用更新时间戳辅助) if(my_lock.try_lock()){ for (int i=0; i<n; ++i) std::cout << c; std::cout << '\n'; } } void run_one(int &n){ std::call_once(flag, [&n]{n=n+1;}); //只执行一次, 适合延迟加载; 多线程static变量状况 } int main () { std::vector<std::thread> ver; int num = 0; for (auto i = 0; i < 10; ++i){ ver.emplace_back(print_block,50,'*'); ver.emplace_back(run_one, std::ref(num)); } for (auto &t : ver){ t.join(); } std::cout << num << std::endl; return 0; }

参考