C++11中的mutex, lock, condition variable实现分析
作者:hengyunabc 发布时间:[ 2016/9/22 11:13:47 ] 推荐标签:测试开发技术 C++
可以看到多参数的std::lock的实现是:
先获取一个锁,然后再调用std::try_lock去获取剩下的锁,如果失败了,则下次先获取上次失败的锁。
重复上面的过程,直到成功获取到所有的锁。
上面的算法用比较巧妙的方式实现了参数的轮转。
std::timed_mutex
std::timed_mutex 是里面封装了mutex和condition,这样两个函数可以用:
try_lock_for
try_lock_until
实际上是posix的mutex和condition的包装。
class timed_mutex
{
mutex __m_;
condition_variable __cv_;
bool __locked_;
public:
timed_mutex();
~timed_mutex();
private:
timed_mutex(const timed_mutex&); // = delete;
timed_mutex& operator=(const timed_mutex&); // = delete;
public:
void lock();
bool try_lock() _NOEXCEPT;
template
_LIBCPP_INLINE_VISIBILITY
bool try_lock_for(const chrono::duration& __d)
{return try_lock_until(chrono::steady_clock::now() + __d);}
template
bool try_lock_until(const chrono::time_point& __t);
void unlock() _NOEXCEPT;
};
template
bool
timed_mutex::try_lock_until(const chrono::time_point& __t)
{
using namespace chrono;
unique_lock __lk(__m_);
bool no_timeout = _Clock::now()
std::recursive_mutex和std::recursive_timed_mutex
这两个实际上是std::mutex和std::timed_mutex 的recursive模式的实现,即锁得获得者可以重复多次调用lock()函数。
和posix mutex里的recursive mutex是一样的。
看下std::recursive_mutex的构造函数知道了。
recursive_mutex::recursive_mutex()
{
pthread_mutexattr_t attr;
int ec = pthread_mutexattr_init(&attr);
if (ec)
goto fail;
ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if (ec)
{
pthread_mutexattr_destroy(&attr);
goto fail;
}
ec = pthread_mutex_init(&__m_, &attr);
if (ec)
{
pthread_mutexattr_destroy(&attr);
goto fail;
}
ec = pthread_mutexattr_destroy(&attr);
if (ec)
{
pthread_mutex_destroy(&__m_);
goto fail;
}
return;
fail:
__throw_system_error(ec, "recursive_mutex constructor failed");
}
std::cv_status
这个用来表示condition等待返回的状态的,和上面的三个表示lock的状态的用途差不多。
enum cv_status
{
no_timeout,
timeout
};
std::condition_variable
包装了posix condition variable。
class condition_variable
{
pthread_cond_t __cv_;
public:
condition_variable() {__cv_ = (pthread_cond_t)PTHREAD_COND_INITIALIZER;}
~condition_variable();
private:
condition_variable(const condition_variable&); // = delete;
condition_variable& operator=(const condition_variable&); // = delete;
public:
void notify_one() _NOEXCEPT;
void notify_all() _NOEXCEPT;
void wait(unique_lock& __lk) _NOEXCEPT;
template
void wait(unique_lock& __lk, _Predicate __pred);
template
cv_status
wait_until(unique_lock& __lk,
const chrono::time_point& __t);
template
bool
wait_until(unique_lock& __lk,
const chrono::time_point& __t,
_Predicate __pred);
template
cv_status
wait_for(unique_lock& __lk,
const chrono::duration& __d);
template
bool
wait_for(unique_lock& __lk,
const chrono::duration& __d,
_Predicate __pred);
typedef pthread_cond_t* native_handle_type;
_LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__cv_;}
private:
void __do_timed_wait(unique_lock& __lk,
chrono::time_point) _NOEXCEPT;
};
里面的函数都是符合直觉的实现,值得注意的是:
cv_status是通过判断时间而确定的,如果超时的则返回cv_status::timeout,如果没有超时,则返回cv_status::no_timeout。
condition_variable::wait_until函数可以传入一个predicate,即一个用户自定义的判断是否符合条件的函数。这个也是很常见的模板编程的方法了。
template
cv_status
condition_variable::wait_until(unique_lock& __lk,
const chrono::time_point& __t)
{
using namespace chrono;
wait_for(__lk, __t - _Clock::now());
return _Clock::now()
bool
condition_variable::wait_until(unique_lock& __lk,
const chrono::time_point& __t,
_Predicate __pred)
{
while (!__pred())
{
if (wait_until(__lk, __t) == cv_status::timeout)
return __pred();
}
return true;
}
std::condition_variable_any
std::condition_variable_any的接口和std::condition_variable一样,不同的是std::condition_variable只能使用std::unique_lock,而std::condition_variable_any可以使用任何的锁对象。
下面来看下为什么std::condition_variable_any可以使用任意的锁对象。
class _LIBCPP_TYPE_VIS condition_variable_any
{
condition_variable __cv_;
shared_ptr __mut_;
public:
condition_variable_any();
void notify_one() _NOEXCEPT;
void notify_all() _NOEXCEPT;
template
void wait(_Lock& __lock);
template
void wait(_Lock& __lock, _Predicate __pred);
template
cv_status
wait_until(_Lock& __lock,
const chrono::time_point& __t);
template
bool
wait_until(_Lock& __lock,
const chrono::time_point& __t,
_Predicate __pred);
template
cv_status
wait_for(_Lock& __lock,
const chrono::duration& __d);
template
bool
wait_for(_Lock& __lock,
const chrono::duration& __d,
_Predicate __pred);
};
可以看到,在std::condition_variable_any里,用shared_ptr __mut_来包装了mutex。所以一切都明白了,回顾std::unique_lock,它包装了mutex,当析构时自动释放mutex。在std::condition_variable_any里,这份工作让shared_ptr来做了。
因此,也可以很轻松得出std::condition_variable_any会比std::condition_variable稍慢的结论了。
其它的东东:
sched_yield()函数的man手册:
sched_yield() causes the calling thread to relinquish the CPU. The thread is moved to the end of the queue for its
static priority and a new thread gets to run.
在C++14里还有std::shared_lock和std::shared_timed_mutex,但是libc++里还没有对应的实现,因此不做分析。
总结
llvm libc++中的各种mutex, lock, condition variable实际上是封闭了posix里的对应实现。封装的技巧和一些细节值得细细推敲学习。
看完了实现源码之后,对于如何使用更加清晰了。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南