互斥量
- 用于线程同步,保证多线程访问共享数据的正确性
基本类型
std::mutex:独占的互斥量,不能递归使用
- std::mutex不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。
- lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:(1). 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。(2).** 如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。**(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
- unlock(), 解锁,释放对互斥量的所有权。
- try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况,(1). 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量。(2). 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
std::timed_mutex:有超时功能的独占互斥量,不能递归使用
- **try_lock_for **函数接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞住(与 std::mutex 的 try_lock() 不同,try_lock 如果被调用时没有获得锁则直接返回 false),如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。参数为超时时间durantion。
- **try_lock_until **函数则接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。参数为时间点time_point
std::recursive_mutex:递归互斥量,能递归使用
- std::recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁),来获得对互斥量对象的多层所有权,std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),可理解为 lock() 次数和 unlock() 次数相同,除此之外,std::recursive_mutex 的特性和 std::mutex 大致相同。
std::recursive_timed_mutex:有超时功能的递归互斥量
- 尽量不要使用递归互斥量
- 容易产生程序逻辑问题
- 效率比非递归锁低
- 重复获得互斥量的最大次数不明确
std::shared_mutex(C++14)
- std::shared_mutex用于管理可转移和共享所有权的互斥对象,适用场景比较特殊:一个或多个读线程同时读取共享资源,且只有一个写线程来修改这个资源,这种情况下才能从shared_mutex获取性能优势(Shared mutexes are usually used in situations when multiple readers can access the same resource at the same time without causing data races, but only one writer can do so.)
- VC第一个支持shared_mutex的版本是VS2015 update2
- http://en.cppreference.com/w/cpp/thread/shared_mutex
基本操作
lock&unlock
// C++_Mutex_Sample.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <mutex>
#include <thread>
#include <iostream>
std::mutex g_lck;
void fun()
{
g_lck.lock();
std::cout << "thread " << std::this_thread::get_id() << " Do something_Begin " << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "thread " << std::this_thread::get_id() << " Do something_End" << std::endl;
g_lck.unlock();
}
int main()
{
std::thread thA(fun);
std::thread thB(fun);
std::thread thC(fun);
thA.join();
thB.join();
thC.join();
return 0;
}
std::lock_gurad包装std::mutex
// C++_Mutex_Sample.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <mutex>
#include <thread>
#include <iostream>
std::mutex g_lck;
void fun()
{
std::lock_guard<std::mutex> lck(g_lck);
std::cout << "thread " << std::this_thread::get_id() << " Do something_Begin " << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "thread " << std::this_thread::get_id() << " Do something_End" << std::endl;
}
int main()
{
std::thread thA(fun);
std::thread thB(fun);
std::thread thC(fun);
thA.join();
thB.join();
thC.join();
return 0;
}
std::recursive_mutex(解决递归死锁问题)
//死锁出错
struct Complex
{
std::mutex mt;
int i;
Complex():i(1) {}
void mul(int x)
{
std::lock_guard<std::mutex> lck(mt);
i *= x;
std::cout << "i = " << i << std::endl;
}
void div(int x)
{
std::lock_guard<std::mutex> lck(mt);
i /= x;
std::cout << "i = " << i << std::endl;
}
void Calc(int x, int y)
{
std::lock_guard<std::mutex> lck(mt);
mul(x);
div(y);
}
};
int main()
{
Complex complex;
complex.Calc(12, 4);
return 0;
}
//解决方案1
struct Complex
{
std::recursive_mutex mt;
int i;
Complex():i(1) {}
void mul(int x)
{
std::lock_guard<std::recursive_mutex> lck(mt);
i *= x;
std::cout << "i = " << i << std::endl;
}
void div(int x)
{
std::lock_guard<std::recursive_mutex> lck(mt);
i /= x;
std::cout << "i = " << i << std::endl;
}
void Calc(int x, int y)
{
std::lock_guard<std::recursive_mutex> lck(mt);
mul(x);
div(y);
}
};
int main()
{
Complex complex;
complex.Calc(12, 4);
return 0;
}
//解决方案2
struct Complex
{
std::mutex mt;
int i;
Complex():i(1) {}
void mul(int x)
{
std::lock_guard<std::mutex> lck(mt);
i *= x;
std::cout << "i = " << i << std::endl;
}
void div(int x)
{
std::lock_guard<std::mutex> lck(mt);
i /= x;
std::cout << "i = " << i << std::endl;
}
void Calc(int x, int y)
{
//std::lock_guard<std::mutex> lck(mt);
mul(x);
div(y);
}
};
int main()
{
Complex complex;
complex.Calc(12, 4);
return 0;
}
std::timed_mutex(基本示例)
std::timed_mutex g_timeLock;
void Work()
{
while (true)
{
if (g_timeLock.try_lock_for(std::chrono::milliseconds(1000)))
{
std::cout << "thread " << std::this_thread::get_id() << " Do something with time mutex" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
g_timeLock.unlock();
}
else
{
std::cout << "thread " << std::this_thread::get_id() << " Do something without mutex" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}
//std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}
}
int main()
{
std::thread t1(Work);
std::thread t2(Work);
t1.join();
t2.join();
return 0;
}
std::timed_mutex(try_lock_for/try_lock_until)
//一直让Work函数得不到g_timeLock,观察超时时间
std::t
imed_mutex g_timeLock;
void Work()
{
while (true)
{
if (g_timeLock.try_lock_for(std::chrono::milliseconds(3000)))
//std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
//if (g_timeLock.try_lock_until(now + std::chrono::milliseconds(3000)))
{
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::cout << "thread " << std::this_thread::get_id() << " Do something with time mutex" << std::put_time(std::localtime(&t), "%Y-%m-%d %H.%M.%S") <<std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
g_timeLock.unlock();
}
else
{
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::cout << "thread " << std::this_thread::get_id() << " Do something without mutex" << std::put_time(std::localtime(&t), "%Y-%m-%d %H.%M.%S") << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
}
}
}
int main()
{
std::lock_guard<std::timed_mutex> lck(g_timeLock);
std::thread t1(Work);
t1.join();
return 0;
}
锁(互斥量管理类)
std::lock_guard
- std::lock_guard严格基于作用域(scope-based)的锁管理类模板,构造时是否加锁是可选的(不加锁时假定当前线程已经获得锁的所有权),析构时自动释放锁,所有权不可转移,对象生存期内不允许手动加锁和释放锁。在默认构造函数里锁定互斥量,即调用互斥量的lock函数;析构函数里解锁互斥量,即调用互斥量的unlock函数
- std::lock_guard 对象并不负责管理 Mutex 对象的生命周期,lock_guard 对象只是简化了 Mutex 对象的上锁和解锁操作,方便线程对互斥量上锁,即在某个 lock_guard 对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而 lock_guard 的生命周期结束之后,它所管理的锁对象会被解锁。
- lock_gurad的构造函数
locking (1) explicit lock_guard (mutex_type& m);
- lock_guard 对象管理 Mutex 对象 m,并在构造时对 m 进行上锁(调用 m.lock())。
adopting (2) lock_guard (mutex_type& m, adopt_lock_t tag);
- lock_guard 对象管理 Mutex 对象 m,与 locking 初始化(1) 不同的是, Mutex 对象 m 已被当前线程锁住。
copy [deleted](3) lock_guard (const lock_guard&) = delete;
lock_guard 对象的拷贝构造和移动构造(move construction),赋值运算符均被禁用,因此 lock_guard 对象不可被拷贝构造或移动构造。
template<class _Mutex>
class lock_guard<_Mutex>
{ // specialization for a single mutex
public:
typedef _Mutex mutex_type;
explicit lock_guard(_Mutex& _Mtx)
: _MyMutex(_Mtx)
{ // construct and lock
_MyMutex.lock();
}
lock_guard(_Mutex& _Mtx, adopt_lock_t)
: _MyMutex(_Mtx)
{ // construct but don't lock
}
~lock_guard() _NOEXCEPT
{ // unlock
_MyMutex.unlock();
}
lock_guard(const lock_guard&) = delete;
lock_guard& operator=(const lock_guard&) = delete;
private:
_Mutex& _MyMutex;
};
std::unique_lock
- 与std:::lock_gurad基本一致,但更加灵活的锁管理类模板,构造时是否加锁是可选的,在对象析构时如果持有锁会自动释放锁,所有权可以转移。对象生命期内允许手动加锁和释放锁。但提供了更好的上锁和解锁控制(lock, unlock, try_lock等接口),尤其是在程序抛出异常后先前已被上锁的 Mutex 对象可以正确进行解锁操作,极大地简化了程序员编写与 Mutex 相关的异常处理代码。
- unique_lock 对象以独占所有权的方式( unique owership)管理 mutex 对象的上锁和解锁操作,所谓独占所有权,就是没有其他的 unique_lock 对象同时拥有某个 mutex 对象的所有权。
- std::unique_lock同样不能拷贝构造,但可以移动构造,在构造(或移动(move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作。如果被赋值的对象之前已经获得了它所管理的 Mutex 对象的锁,则在移动赋值(move assignment)之前会调用 unlock 函数释放它所占有的锁。
template<class _Mutex>
class unique_lock
{ // whizzy class with destructor that unlocks mutex
public:
typedef unique_lock<_Mutex> _Myt;
typedef _Mutex mutex_type;
// CONSTRUCT, ASSIGN, AND DESTROY
//默认构造函数不管理任何Mutex对象
unique_lock() _NOEXCEPT
: _Pmtx(0), _Owns(false)
{ // default construct
}
//传入Mutex对象,并尝试调用Mutex对象的lock()进行上锁
//如果有另外的unique_lock对象已经管理了该Mutex对象,则当前线程会被阻塞
explicit unique_lock(_Mutex& _Mtx)
: _Pmtx(&_Mtx), _Owns(false)
{ // construct and lock
_Pmtx->lock();
_Owns = true;
}
//传入Mutex对象,该Mutex对象已经被当前进程锁住了
unique_lock(_Mutex& _Mtx, adopt_lock_t)
: _Pmtx(&_Mtx), _Owns(true)
{ // construct and assume already locked
}
//传入Mutex对象,不会锁住该Mutex对象
unique_lock(_Mutex& _Mtx, defer_lock_t) _NOEXCEPT
: _Pmtx(&_Mtx), _Owns(false)
{ // construct but don't lock
}
//传入Mutex对象,并尝试调用Mutex对象的try_lock()进行上锁
//上锁不成功,当前线程也不会阻塞
unique_lock(_Mutex& _Mtx, try_to_lock_t)
: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock())
{ // construct and try to lock
}
//传入Mutex对象,并尝试调用Mutex对象的try_lock_for(rel_time)进行上锁
//锁住一段时间
template<class _Rep,
class _Period>
unique_lock(_Mutex& _Mtx,
const chrono::duration<_Rep, _Period>& _Rel_time)
: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_for(_Rel_time))
{ // construct and lock with timeout
}
}
//传入Mutex对象,并尝试调用Mutex对象的try_lock_until(rel_time)进行上锁
//在某个时间点前锁住
template<class _Clock,
class _Duration>
unique_lock(_Mutex& _Mtx,
const chrono::time_point<_Clock, _Duration>& _Abs_time)
: _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_until(_Abs_time))
{ // construct and lock with timeout
}
unique_lock(_Mutex& _Mtx, const xtime *_Abs_time)
: _Pmtx(&_Mtx), _Owns(false)
{ // try to lock until _Abs_time
_Owns = _Pmtx->try_lock_until(_Abs_time);
}
unique_lock(unique_lock&& _Other) _NOEXCEPT
: _Pmtx(_Other._Pmtx), _Owns(_Other._Owns)
{ // destructive copy
_Other._Pmtx = 0;
_Other._Owns = false;
}
unique_lock& operator=(unique_lock&& _Other)
{ // destructive copy
if (this != &_Other)
{ // different, move contents
if (_Owns)
_Pmtx->unlock();
_Pmtx = _Other._Pmtx;
_Owns = _Other._Owns;
_Other._Pmtx = 0;
_Other._Owns = false;
}
return (*this);
}
~unique_lock() _NOEXCEPT
{ // clean up
if (_Owns)
_Pmtx->unlock();
}
unique_lock(const unique_lock&) = delete;
unique_lock& operator=(const unique_lock&)
...
};
std::unique_lock的主要成员函数
- 上锁/解锁操作:lock,try_lock,try_lock_for,try_lock_until 和unlock
- 移动赋值:move Assignment.
- 交换:swap
- 释放:release
- 是否获得了锁:owns_lock,operator bool()
- 得到管理的mutex对象指针:mutex
template<class _Mutex>
class unique_lock
{ // whizzy class with destructor that unlocks mutex
public:
...
// LOCK AND UNLOCK
void lock()
{ // lock the mutex
_Validate();
_Pmtx->lock();
_Owns = true;
}
bool try_lock()
{ // try to lock the mutex
_Validate();
_Owns = _Pmtx->try_lock();
return (_Owns);
}
template<class _Rep,
class _Period>
bool try_lock_for(const chrono::duration<_Rep, _Period>& _Rel_time)
{ // try to lock mutex for _Rel_time
_Validate();
_Owns = _Pmtx->try_lock_for(_Rel_time);
return (_Owns);
}
template<class _Clock,
class _Duration>
bool try_lock_until(
const chrono::time_point<_Clock, _Duration>& _Abs_time)
{ // try to lock mutex until _Abs_time
_Validate();
_Owns = _Pmtx->try_lock_until(_Abs_time);
return (_Owns);
}
bool try_lock_until(const xtime *_Abs_time)
{ // try to lock the mutex until _Abs_time
_Validate();
_Owns = _Pmtx->try_lock_until(_Abs_time);
return (_Owns);
}
void unlock()
{ // try to unlock the mutex
if (!_Pmtx || !_Owns)
_THROW_NCEE(system_error,
_STD make_error_code(errc::operation_not_permitted));
_Pmtx->unlock();
_Owns = false;
}
// MUTATE
void swap(unique_lock& _Other) _NOEXCEPT
{ // swap with _Other
_STD swap(_Pmtx, _Other._Pmtx);
_STD swap(_Owns, _Other._Owns);
}
_Mutex *release() _NOEXCEPT
{ // disconnect
_Mutex *_Res = _Pmtx;
_Pmtx = 0;
_Owns = false;
return (_Res);
}
// OBSERVE
bool owns_lock() const _NOEXCEPT
{ // return true if this object owns the lock
return (_Owns);
}
explicit operator bool() const _NOEXCEPT
{ // return true if this object owns the lock
return (_Owns);
}
_Mutex *mutex() const _NOEXCEPT
{ // return pointer to managed mutex
return (_Pmtx);
}
...
}
std::unique_lock的使用
- lock: 上锁操作,调用它所管理的 Mutex 对象的 lock 函数。如果在调用 Mutex 对象的 lock 函数时该 Mutex 对象已被另一线程锁住,则当前线程会被阻塞,直到它获得了锁。 该函数返回时,当前的 unique_lock 对象便拥有了它所管理的 Mutex 对象的锁。如果上锁操作失败,则抛出 system_error 异常。
std::mutex mtx;
void print_thread_id(int id)
{
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
lock.lock();
std::cout << "thread #" << id << '\n';
lock.unlock();
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++){
threads.emplace_back(print_thread_id, i + 1);
}
for (auto &th : threads){
th.join();
}
}
//output
thread #1
thread #5
thread #3
thread #10
thread #2
thread #6
thread #7
thread #8
thread #9
thread #4
- try_lock: 上锁操作,调用它所管理的 Mutex 对象的 try_lock 函数,如果上锁成功,则返回 true,否则返回 false。
std::mutex mtx;
void print_star(int id)
{
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
if (lock.try_lock()) {
std::cout << "*";
}
else {
std::cout << "x";
}
std::this_thread::sleep_for(std::chrono::microseconds(1000));
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 500; i++) {
threads.emplace_back(print_star, i + 1);
}
for (auto &th : threads) {
th.join();
}
}
//output
*xxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxx*xxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxx*xxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxx*xxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxx
- try_lock_for: 上锁操作,调用它所管理的 Mutex 对象的 try_lock_for 函数,如果上锁成功,则返回 true,否则返回 false。
std::timed_mutex mtt;
void fireworks()
{
std::unique_lock<std::timed_mutex> lock(mtt, std::defer_lock);
while (!lock.try_lock_for(std::chrono::microseconds(200))) {
std::cout << "-";
}
std::this_thread::sleep_for(std::chrono::microseconds(1000));
std::cout << "*\n";
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
threads.emplace_back(fireworks);
}
for (auto &th : threads) {
th.join();
}
}
//output
*
---------*
--------*
-------------*
-----*
----*
---*
--*
-*
-*
- try_lock_until: 上锁操作,调用它所管理的 Mutex 对象的 try_lock_for 函数,如果上锁成功,则返回 true,否则返回 false。
std::timed_mutex cinderella;
void carriage()
{
std::unique_lock<std::timed_mutex> lock(cinderella, std::defer_lock);
if (lock.try_lock_until(std::chrono::system_clock::now() + std::chrono::seconds(2))) {
std::cout << "ride back home on carriage\n";
lock.unlock();
}
else {
std::cout << "carriage reverts to pumpkin\n";
}
}
void ball()
{
std::unique_lock<std::timed_mutex> lock(cinderella, std::defer_lock);
lock.lock();
std::cout << "at the ball...\n";
std::this_thread::sleep_for(std::chrono::seconds(3));
}
int main()
{
std::thread th1(ball);
std::thread th2(carriage);
th1.join();
th2.join();
}
//output
at the ball...
carriage reverts to pumpkin
- release: 返回指向它所管理的 Mutex 对象的指针,并释放所有权。
std::mutex mtx;
std::atomic<int> count;
void print_count_and_unlock(std::mutex* p_mtx)
{
std::this_thread::sleep_for(std::chrono::microseconds(1000));
std::cout << "count: " << count << '\n';
p_mtx->unlock();
}
void task()
{
std::unique_lock<std::mutex> lock(mtx);
++count;
print_count_and_unlock(lock.release());
}
int main()
{
count = 0;
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
threads.emplace_back(task);
}
for (auto &th : threads) {
th.join();
}
}
//output
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
count: 8
count: 9
count: 10
- owns_lock & operator bool(): 返回当前 std::unique_lock 对象是否获得了锁。
std::mutex mtx;
void print_star()
{
std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);
//if (lock.owns_lock()) {
if (lock) {
std::cout << '*';
}
else {
std::cout << 'x';
}
std::this_thread::sleep_for(std::chrono::microseconds(1000));
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 500; i++) {
threads.emplace_back(print_star);
}
for (auto &th : threads) {
th.join();
}
}
//output
*xxxxx*xxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxx*xxxxxxxxxxx*xxxxxxxxxxxxxx
- mutex: 返回当前 std::unique_lock 对象所管理的 Mutex 对象的指针。
class MyMutex : public std::mutex {
int m_id;
public:
MyMutex(int id) :m_id(id)
{
}
int id()
{
return m_id;
}
};
MyMutex mtx(100);
void print_ids(int id)
{
std::unique_lock<MyMutex> lock(mtx);
std::cout << "thread #" << id << " locked mutex " << lock.mutex()->id() << '\n';
std::this_thread::sleep_for(std::chrono::microseconds(1000));
}
int main()
{
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
threads.emplace_back(print_ids, i+1);
}
for (auto &th : threads) {
th.join();
}
}
//output
thread #1 locked mutex 100
thread #2 locked mutex 100
thread #3 locked mutex 100
thread #4 locked mutex 100
thread #5 locked mutex 100
thread #6 locked mutex 100
thread #7 locked mutex 100
thread #8 locked mutex 100
thread #9 locked mutex 100
thread #10 locked mutex 100
std::shared_lock
- shared_lock是read lock。搭配std::shared_mutex使用,被锁后仍允许其他线程执行同样被shared_lock的代码。
- lock_guard和unique_lock是write lock。被锁后不允许其他线程执行被shared_lock或unique_lock的代码。
typedef std::shared_lock<std::shared_mutex> ReadLock;
typedef std::lock_guard<std::shared_mutex> WriteLock;
int ReconCoordinator::SearchPort(int jobId)
{
int port = 0;
ReadLock lck(m_mtConn);
auto it = m_jobIdAndPort.find(jobId);
if (it != m_jobIdAndPort.end()) {
port = it->second;
}
return port;
}
void ReconCoordinator::FlushConn()
{
int jobId = 0;
bool flushFlag = false;
{
std::lock_guard<std::mutex> erupLock(m_mtErup);
ReadLock lck(m_mtConn);
for (auto it = m_jobIdAndConn.begin(); it != m_jobIdAndConn.end(); it++) {
try {
std::shared_ptr<ErupProcServiceClient> procClient = it->second->GetSrvClient<ErupProcServiceClient>();
procClient->Alive();
}
catch (TException&) {
flushFlag = true;
jobId = it->first;
break;
}
}
}
if (flushFlag) {
if (jobId > ERUP_STANDBY_ID_MAX) {
rcLog.LOG_WARN("ReconCoordinator, Zombie erup conn flush, jobId: %d", jobId);
}
else {
rcLog.LOG_WARN("ReconCoordinator, Buffered zombie erup conn flush");
}
DestroyProcess(jobId);
NotifyError(jobId);
}
}
void ReconCoordinator::ClearPortInfo(int jobId)
{
WriteLock lck(m_mtInfo);
m_requiredInfo->ClearProtInfo(jobId);
}
void ReconCoordinator::InitFailed(int jobId)
{
//rcLog.LOG_WARN("Erup process initialize failed, jobId: %d", jobId);
if (jobId <= ERUP_STANDBY_ID_MAX)
{
{
WriteLock lck(m_mtConn);
m_jobIdAndPort.erase(jobId);
}
{
WriteLock lck(m_mtState);
m_jobIdAndState.erase(jobId);
}
{
std::lock_guard<std::mutex> lck(m_mtProc);
auto it = m_jobIdAndProcess.find(jobId);
if (it == m_jobIdAndProcess.end()) {
rcLog.LOG_INFO("Erup process not exists in NotifyInitFailed, jobId: %d", jobId);
}
else {
::TerminateProcess(it->second, 0);
::CloseHandle(it->second);
m_jobIdAndProcess.erase(it);
}
}
}
}
加锁策略参数
- 互质量管理类在构造时是否加锁是可选的,C++11提供了以下3种加锁策略,及其支持情况
策略 | tag type | 描述 |
---|---|---|
(默认) | 无 | 请求锁,阻塞当前线程直到成功获得锁。 |
std::defer_lock | std::defer_lock_t | 不请求锁。 |
std::try_to_lock | std::try_to_lock_t | 尝试请求锁,但不阻塞线程,锁不可用时也会立即返回。 |
std::adopt_lock | std::adopt_lock_t | 假定当前线程已经获得互斥对象的所有权,所以不再请求锁。 |
策略 | 描述 | std::lock_guard | std::unique_lock | std::shared_lock |
---|---|---|---|---|
(默认) | 请求锁,阻塞当前线程直到成功获得锁。 | √ | √ | √(共享) |
std::defer_lock | 不请求锁。 | × | √ | √ |
std::try_to_lock | 尝试请求锁,但不阻塞线程,锁不可用时也会立即返回。 | × | √ | √ |
std::adopt_lock | 假定当前线程已经获得互斥对象的所有权,所以不再请求锁。 | √ | √ | √ |
官方解释:https://zh.cppreference.com/w/cpp/thread/lock_tag
原子锁操作
- 有时需要同时对多个互斥量上锁,可使用:std::lock和std::try_lock
std::lock(mt1, mt2)