1.1 互斥量类型 mutex
不支持赋值/移动拷贝;
1.1.1 std:mutex & timed_mutex
互斥量类,该类型有如下几个特性:
-
当一个线程调用 m.lock 函数获取到他,只有本线程有资格释放他,其他线程就无法再获取或者释放,也就说即使他被定义为了全局对象,之后如果有一个线程对该mutex上锁,那么其他线程对他上锁就会被阻塞,对他解锁就会直接报出异常;
-
该类型禁止拷贝或者移动拷贝;
-
当一个线程占有了一个mutex,但是在thread结束之前未对其解锁就会产生未定义行为;如果一个mutex对象被一个thread上锁,但是mutex对象被析构了而未对其解锁也会产生未定义行为;
class __mutex_base {
protected:
typedef pthread_mutex_t __native_type;
__native_type _M_mutex; // pthread_mutex_t;
__mutex_base() noexcept
{
// XXX EAGAIN, ENOMEM, EPERM, EBUSY(may), EINVAL(may)
__GTHREAD_MUTEX_INIT_FUNCTION(&_M_mutex);
}
~__mutex_base() noexcept { __gthread_mutex_destroy(&_M_mutex); }
#endif
__mutex_base(const __mutex_base&) = delete;
__mutex_base& operator=(const __mutex_base&) = delete;
};
/// The standard mutex type.
class mutex : private __mutex_base{
public:
typedef __native_type* native_handle_type;
constexpr mutex() noexcept = default;
~mutex() = default;
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
void lock() {
int __e = pthread_mutex_lock(&_M_mutex); // 系统调用;
// EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
if (__e)
__throw_system_error(__e);
}
bool try_lock() noexcept
{
// XXX EINVAL, EAGAIN, EBUSY
return !pthread_mutex_trylock(&_M_mutex); // 系统调用;
}
void unlock(){
// XXX EINVAL, EAGAIN, EPERM
pthread_mutex_unlock(&_M_mutex); // 系统调用;
}
native_handle_type native_handle() noexcept{
return &_M_mutex;
}
};
带等待时间的互斥量:只是简单地比mutex多了几个带有等待时间的 lock函数而已;
// 比普通的 mutex类多继承了一个 __timed_mutex_impl模板类(里面定义了一些带有时间的上锁成员函数);
class timed_mutex: private __mutex_base, public __timed_mutex_impl<timed_mutex>
{
public:
timed_mutex() = default;
~timed_mutex() = default;
timed_mutex(const timed_mutex&) = delete;
timed_mutex& operator=(const timed_mutex&) = delete;
void lock(){
int __e = pthread_mutex_lock(&_M_mutex);
// EINVAL, EAGAIN, EBUSY, EINVAL, EDEADLK(may)
if (__e)
__throw_system_error(__e);
}
bool try_lock() noexcept {
// XXX EINVAL, EAGAIN, EBUSY
return !pthread_mutex_trylock(&_M_mutex);
}
// 尝试上锁阻塞一段相对时间,就是在内部调用基类的成员函数;
template <class _Rep, class _Period>
bool try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{ return _M_try_lock_for(__rtime); }
// 尝试上锁阻塞到一个时钟系统下的绝对时间点,就是在内部调用基类的成员函数;
template <class _Clock, class _Duration>
bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{ return _M_try_lock_until(__atime); }
// 解锁;
void unlock(){
// XXX EINVAL, EAGAIN, EBUSY
pthread_mutex_unlock(&_M_mutex);
}
// 返回内部的pthread_mutex_t*;
pthread_mutex_t* native_handle() noexcept
{ return &_M_mutex; }
private:
friend class __timed_mutex_impl<timed_mutex>;
// 阻塞等待一段相对时间,timespec是一个由 s 和 ns 两个成员组成的时间间隔结构体;
bool _M_timedlock(const timespec& __ts)
{ return !pthread_mutex_timedlock(&_M_mutex, &__ts); }
// 指定一个时钟系统,然后阻塞到该系统下的一个绝对时间点,这个绝对时间是通过从该时钟系统启动的纪元时间epoch到目标时间的时间间隔表示;clockid_t就是int类型表示的时间,表示一个时钟系统类型;
bool _M_clocklock(clockid_t clockid, const timespec& __ts)
{ return !pthread_mutex_clocklock(&_M_mutex, clockid, &__ts); }
};
// 内部类型
template<typename _Derived>
class __timed_mutex_impl {
protected:
template<typename _Rep, typename _Period>
bool _M_try_lock_for(const chrono::duration<_Rep, _Period>& __rtime){
using __clock = chrono::steady_clock;
auto __rt = chrono::duration_cast<__clock::duration>(__rtime);
if (ratio_greater<__clock::period, _Period>())
++__rt;
return _M_try_lock_until(__clock::now() + __rt);
}
// 下面为不同时钟系统的try_lock_until函数;
template<typename _Duration>
bool _M_try_lock_until(const chrono::time_point<chrono::system_clock, _Duration>& __atime){
auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
__gthread_time_t __ts = {
static_cast<std::time_t>(__s.time_since_epoch().count()),
static_cast<long>(__ns.count())
};
return static_cast<_Derived*>(this)->_M_timedlock(__ts);
}
template<typename _Duration>
bool _M_try_lock_until(const chrono::time_point<chrono::steady_clock, _Duration>& __atime){ ... } // 代码和上面一样,省略;
template<typename _Clock, typename _Duration>
bool _M_try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime){...}
};
chrono时间库:
(1)duration类:chrono::duration是表示时间段的类型,是一段时间,其中第一个模板是用什么类型来表示一段时间,第二个模板是一段时间持续的秒数s,通过std::ratio有理数分数类型来表示,std::ratio也是一个模板类,他的第一个参数为分子,第二个参数为分母;
template<typename _Rep, typename _Period> // _Period需要通过ratio类来传入;
struct duration {
private:
_Rep __r; // 表示时间总长的成员变量,粒度为 _Period秒;假如 __r=2,std::ratio<60,1>的话,这个duration实例对象表示的时间长度就是2s;count函数就是直接返回该对象;
public:
using rep = _Rep;
using period = typename _Period::type; // 这也是个ratio类,就是相当于给原来的ratio类起了一个别名而已;
// ...
// construction / copy / destroy都有;
constexpr duration() = default;
duration(const duration&) = default; // 默认拷贝构造;
constexpr duration(const duration<_Rep2, _Period2>& __d) :__r(duration_cast<duration>(__d).count()) { } // 类型转换拷贝构造,当被用于初始化的duration的_Period和当前的不一样就会优先调用该函数;
// ...一些加减乘除运算符重载;
// 返回长度成员;
constexpr rep count() const { return __r; }
};
// 有理数类型,用作表示duration的_Period模板参数;
template<intmax_t _Num, intmax_t _Den = 1>
struct ratio {
...
// Note: sign(N) * abs(N) == N
static constexpr intmax_t num =
_Num * __static_sign<_Den>::value / __static_gcd<_Num, _Den>::value; // 分子;
static constexpr intmax_t den =
__static_abs<_Den>::value / __static_gcd<_Num, _Den>::value; // 分母;
typedef ratio<num, den> type; // 表示该ratio类型调整后的别名,其实就是将本类型时间对齐之后的一个ratio类型;
};
我们还可以直接通过字面值来定义一个duration对象,因为该类型重载了几个不同单位的运算符:
// 下面看一下 ""s 运算符源码:
// 直接返回一个 std::chrono::seconds的 秒为单位的duration类型实例:
constexpr std::chrono::seconds operator""s(unsigned long long s)
{
return std::chrono::seconds(s);
}
// 返回一个 未定义粒度的duration类型实例用于类型转换:
constexpr std::chrono::duration<long double> operator""s(long double s)
{
return std::chrono::duration<long double>(s);
}
// 举例应用:
auto d2 = 2s; // 生成一个std::chrono::seconds类型表示的2s实例;
cout << d2.count() << endl; // 输出2;
auto d2 = 1min; // 生成一个std::chrono::minutes类型表示的1分钟的实例;
cout << d2.count() << endl; // 输出1;
std::chrono::duration<int, ratio<1>> d2 = 1min; // 先生成一个std::chrono::minutes类型表示的1分钟的实例,之后类型转换为std::chrono::seconds类型表示;
cout << d2.count() << endl; // 输出60;
其中在 std::chrono库 中已经预定义好了许多不同单位的duration类:
duration类型转换函数:可以通过duration_cast函数将一个时间粒度的duration转换成另一个粒度来表示;
template<typename _ToDur, typename _Rep, typename _Period>
constexpr duration<_Rep, _Period> duration_cast(const duration<_Rep, _Period>& __d) {
typedef typename _ToDur::period __to_period;
typedef typename _ToDur::rep __to_rep;
typedef ratio_divide<_Period, __to_period> __cf;
typedef typename common_type<__to_rep, _Rep, intmax_t>::type
__cr;
typedef __duration_cast_impl<_ToDur, __cf, __cr,
__cf::num == 1, __cf::den == 1> __dc;
return __dc::__cast(__d); // 转换;
}
// 下面为__duration_cast_impl类的类型转换成员函数;
template<typename _Rep, typename _Period>
static constexpr _ToDur __cast(const duration<_Rep, _Period>& __d) {
typedef typename _ToDur::rep __to_rep;
return _ToDur(static_cast<__to_rep>(static_cast<_CR>(__d.count())
* static_cast<_CR>(_CF::num)
/ static_cast<_CR>(_CF::den))); // 转换之后的duration类;
}