互斥类的最重要成员函数是lock()和unlock()。在进入临界区时,执行lock()加锁操作,如果这时已经被其它线程锁住,则当前线程在此排队等待。退出临界区时,执行unlock()解锁操作。更好的办法是采用”资源分配时初始化”(RAII)方法来加锁、解锁,这避免了在临界区中因为抛出异常或return等操作导致没有解锁就退出的问题。极大地简化了程序员编写mutex相关的异常处理代码。C++11的标准库中提供了std::lock_guard类模板做mutex的RAII。
std::lock_guard类的构造函数禁用拷贝构造,且禁用移动构造。std::lock_guard类除了构造函数和析构函数外没有其它成员函数。
在std::lock_guard对象构造时,传入的mutex对象(即它所管理的mutex对象)会被当前线程锁住。在lock_guard对象被析构时,它所管理的mutex对象会自动解锁,不需要程序员手动调用lock和unlock对mutex进行上锁和解锁操作。lock_guard对象并不负责管理mutex对象的生命周期,lock_guard对象只是简化了mutex对象的上锁和解锁操作,方便线程对互斥量上锁,即在某个lock_guard对象的生命周期内,它所管理的锁对象会一直保持上锁状态;而lock_guard的生命周期结束之后,它所管理的锁对象会被解锁。程序员可以非常方便地使用lock_guard,而不用担心异常安全问题。
std::lock_guard在构造时只被锁定一次,并且在销毁时解锁。
关于std::mutex的基础介绍可以参考: http://blog.csdn.net/fengbingchun/article/details/73521630
The difference is that you can lock and unlock a std::unique_lock. std::lock_guard will be locked only once on construction and unlocked on destruction.
std::unique_lock has other features that allow it to e.g.: be constructed without locking the mutex immediately but to build the RAII wrapper. However, std::unique_lock might have a tad more overhead(较多开销).
std::lock_guard also provides a convenient RAII wrapper, but cannot lock multiple mutexes safely. It can be used when you need a wrapper for a limited scope, e.g.: a member function.
One of the differences between std::lock_guard and std::unique_lock is that the programmer is able to unlock std::unique_lock, but she/he is not able to unlock std::lock_guard.
下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:
-
#include "lock_guard.hpp"
-
#include <iostream>
-
#include <thread>
-
#include <mutex>
-
#include <stdexcept>
-
#include <list>
-
#include <algorithm>
-
-
namespace lock_guard_ {
-
-
///////////////////////////////////////////////////////
-
// reference: http://www.cplusplus.com/reference/mutex/lock_guard/
-
namespace {
-
std::mutex mtx;
-
-
void print_even(int x) {
-
if (x %
2 ==
0)
std::
cout << x <<
" is even\n";
-
else
throw (
std::logic_error(
"not even"));
-
}
-
-
void print_thread_id(int id) {
-
try {
-
// using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
-
std::lock_guard<
std::mutex> lck(mtx);
-
print_even(id);
-
}
catch (
std::logic_error&) {
-
std::
cout <<
"[exception caught]\n";
-
}
-
}
-
}
-
-
int test_lock_guard_1()
-
{
-
std::thread threads[
10];
-
// spawn 10 threads:
-
for (
int i =
0; i<
10; ++i)
-
threads[i] =
std::thread(print_thread_id, i +
1);
-
-
for (
auto& th : threads) th.join();
-
-
return
0;
-
}
-
-
///////////////////////////////////////////////////////////
-
// reference: http://www.cplusplus.com/reference/mutex/lock_guard/lock_guard/
-
namespace {
-
std::mutex mtx2;
// mutex for critical section
-
-
void print_thread_id2(int id) {
-
mtx2.lock();
-
std::lock_guard<
std::mutex> lck(mtx2,
std::adopt_lock);
-
std::
cout <<
"thread #" << id <<
'\n';
-
}
-
}
-
-
int test_lock_guard_2()
-
{
-
std::thread threads[
10];
-
// spawn 10 threads:
-
for (
int i =
0; i<
10; ++i)
-
threads[i] =
std::thread(print_thread_id2, i +
1);
-
-
for (
auto& th : threads) th.join();
-
-
return
0;
-
}
-
-
////////////////////////////////////////////////////////////
-
// reference: http://en.cppreference.com/w/cpp/thread/lock_guard
-
namespace {
-
int g_i =
0;
-
std::mutex g_i_mutex;
// protects g_i
-
-
void safe_increment()
-
{
-
std::lock_guard<
std::mutex> lock(g_i_mutex);
-
++g_i;
-
-
std::
cout <<
std::this_thread::get_id() <<
": " << g_i <<
'\n';
-
-
// g_i_mutex is automatically released when lock goes out of scope
-
}
-
}
-
-
int test_lock_guard_3()
-
{
-
std::
cout <<
"main: " << g_i <<
'\n';
-
-
std::
thread t1(safe_increment);
-
std::
thread t2(safe_increment);
-
-
t1.join();
-
t2.join();
-
-
std::
cout <<
"main: " << g_i <<
'\n';
-
-
return
0;
-
}
-
-
//////////////////////////////////////////////////////////////////////
-
// reference: http://www.bogotobogo.com/cplusplus/C11/7_C11_Thread_Sharing_Memory.php
-
namespace {
-
// a global variable
-
std::
list<
int> myList;
-
-
// a global instance of std::mutex to protect global variable
-
std::mutex myMutex;
-
-
void addToList(int max, int interval)
-
{
-
// the access to this function is mutually exclusive
-
std::lock_guard<
std::mutex> guard(myMutex);
-
for (
int i =
0; i < max; i++) {
-
if ((i % interval) ==
0) myList.push_back(i);
-
}
-
}
-
-
void printList()
-
{
-
// the access to this function is mutually exclusive
-
std::lock_guard<
std::mutex> guard(myMutex);
-
for (
auto itr = myList.begin(), end_itr = myList.end(); itr != end_itr; ++itr) {
-
std::
cout << *itr <<
",";
-
}
-
}
-
}
-
int test_lock_guard_4()
-
{
-
int max =
100;
-
-
std::
thread t1(addToList, max, 1);
-
std::
thread t2(addToList, max, 10);
-
std::
thread t3(printList);
-
-
t1.join();
-
t2.join();
-
t3.join();
-
-
return
0;
-
}
-
-
}
// namespace lock_guard_
GitHub: https://github.com/fengbingchun/Messy_Test
转载自:https://blog.csdn.net/fengbingchun/article/details/78649260