Mutex 又称互斥量,C++11 中与 Mutex 相关的类(包括锁类型)和函数都声明在 <mutex>
头文件中,所以如果你在程序里面使用 std::mutex
及相关类型和辅助函数,就必须包含 <mutex>
头文件。
C++11 中定义了如下与互斥量和锁相关的类:
-
Mutex 系列类(四种),C++11 标准中规定的与互斥量相关的类包括:
std::mutex
,最基本的 Mutex 类,该类提供了最基本的上锁和解锁操作。同时,基本的互斥量不允许某个线程在已获得互斥量的情况下重复对该互斥量进行上锁操作,所以重复上锁将会导致死锁(结果通常未定义的)。std::recursive_mutex
,递归 Mutex 类,与std::mutex
功能基本相同,但是允许互斥量的拥有者(通常是某个线程)重复对该互斥量进行上锁操作而不会产生死锁,但必须保证上锁和解锁的次数相同。std::time_mutex
,定时 Mutex 类,与std::mutex
功能基本相同,但是提供了两个额外的定时上锁操作,try_lock_for
和try_lock_until
,即某个线程在规定的时间内对互斥量进行上锁操作,如果在规定的时间内获得了锁则返回true
, 超时则返回false
,在本章后面的内容中我会介绍try_lock_for
和try_lock_until
两个上锁函数之间细微的差异。std::recursive_timed_mutex
,定时递归 Mutex 类,既提供了重复上锁功能,又提供了定时上锁的特性(即在规定的时间内没有获得锁则返回false
),相当于std::recursive_mutex
和std::time_mutex
的组合。
-
Lock 类(两种),C++11 标准中定义了两种与互斥量相关的 RAII 技术。(RAII : Resource Acquisition Is Initialization,资源获取即初始化)
std::lock_guard
,与 Mutex RAII 相关,方便线程对互斥量上锁。std::unique_lock
,与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。
-
其他类型
std::once_flag
,call_once
辅助函数会使用到该类型的对象。- (默认) 无请求锁,阻塞当前线程直到成功获得锁。
- std::defer_lock std::defer_lock_t 不请求锁。
- std::try_to_lock std::try_to_lock_t 尝试请求锁,但不阻塞线程,锁不可用时也会立即返回。std::adopt_lock std::adopt_lock_t 假定当前线程已经获得互斥对象的所有权,所以不再请求锁。
-
辅助函数
std::try_lock
,尝试同时对多个互斥量上锁。std::lock
,同时对多个互斥量上锁。std::call_once
,如果多个线程需要同时调用某个函数,call_once
可以保证多个线程对该函数只调用一次。
本章后面会对以上类型和函数进行详细介绍,我们首先来看 <mutex>
头文件中各个类型的摘要吧。
4.1 <mutex>
头文件摘要
<mutex>
头文件摘要如下:
namespace std {
class mutex;
class recursive_mutex;
class timed_mutex;
class recursive_timed_mutex;
struct defer_lock_t { };
struct try_to_lock_t { };
struct adopt_lock_t { };
constexpr defer_lock_t defer_lock { };
constexpr try_to_lock_t try_to_lock { };
constexpr adopt_lock_t adopt_lock { };
template <class Mutex> class lock_guard;
template <class Mutex> class unique_lock;
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y);
template <class L1, class L2, class... L3> int try_lock(L1&, L2&, L3&...);
template <class L1, class L2, class... L3> void lock(L1&, L2&, L3&...);
struct once_flag {
constexpr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
};
template<class Callable, class ...Args>
void call_once(once_flag& flag, Callable func, Args&&... args);
}
4.1.1 std::mutex
类摘要
namespace std {
class mutex {
public:
constexpr mutex();
~mutex();
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
void lock();
bool try_lock() noexcept;
void unlock() noexcept;
typedef implementation-defined native_handle_type;
native_handle_type native_handle();
};
}
4.1.2 std::recursive_mutex
类摘要
namespace std {
class recursive_mutex {
public:
recursive_mutex();
~recursive_mutex();
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete;
void lock();
bool try_lock() noexcept;
void unlock() noexcept;
typedef implementation-defined native_handle_type;
native_handle_type native_handle();
};
}
4.1.3 std::timed_mutex
类摘要
namespace std {
class timed_mutex {
public:
timed_mutex();
~timed_mutex();
timed_mutex(const timed_mutex&) = delete;
timed_mutex& operator=(const timed_mutex&) = delete;
void lock();
bool try_lock();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) noexcept;
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) noexcept;
void unlock();
typedef implementation-defined native_handle_type;
native_handle_type native_handle();
};
}
4.1.4 std::recursive_timed_mutex
类摘要
namespace std {
class recursive_timed_mutex {
public:
recursive_timed_mutex();
~recursive_timed_mutex();
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
void lock();
bool try_lock();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) noexcept;
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) noexcept;
void unlock();
typedef implementation-defined native_handle_type;
native_handle_type native_handle();
};
}
4.1.5 lock_guard
类摘要
template<class _Mutex>
class lock_guard
{ // class with destructor that unlocks a mutex
public:
using mutex_type = _Mutex
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;
};
*/
4.1.6 std::unique_lock
类摘要
namespace std {
template <class Mutex>
class unique_lock {
public:
typedef Mutex mutex_type;
// 构造/拷贝/析构:
unique_lock() noexcept;
explicit unique_lock(mutex_type& m);
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, try_to_lock_t) noexcept;
unique_lock(mutex_type& m, adopt_lock_t) noexcept;
template <class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time) noexcept;
template <class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time) noexcept;
~unique_lock();
unique_lock(unique_lock const&) = delete;
unique_lock& operator=(unique_lock const&) = delete;
unique_lock(unique _lock&& u) noexcept;
unique_lock& operator=(unique_lock&& u) noexcept;
// 上锁操作:
void lock();
bool try_lock();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
void unlock();
// 修改操作
void swap(unique_lock& u) noexcept;
mutex_type *release() noexcept;
// observers:
bool owns_lock() const noexcept;
explicit operator bool () const noexcept;
mutex_type* mutex() const noexcept;
private:
mutex_type *pm; // exposition only
bool owns; // exposition only
};
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
}