为什么std::lock_guard
和std::unique_lock
必须将锁类型指定为模板参数?
考虑以下替代方案。首先,在detail
命名空间中,存在类型擦除类(非模板抽象基类和模板派生类):
#include <type_traits>
#include <mutex>
#include <chrono>
#include <iostream>
namespace detail {
struct locker_unlocker_base {
virtual void lock() = 0;
virtual void unlock() = 0;
};
template<class Mutex>
struct locker_unlocker : public locker_unlocker_base {
locker_unlocker(Mutex &m) : m_m{&m} {}
virtual void lock() { m_m->lock(); }
virtual void unlock() { m_m->unlock(); }
Mutex *m_m;
};
}
现在te_lock_guard
,类型擦除锁保护,在构造时简单地放置一个正确类型的对象(没有动态内存分配):
class te_lock_guard {
public:
template<class Mutex>
te_lock_guard(Mutex &m) {
new (&m_buf) detail::locker_unlocker<Mutex>(m);
reinterpret_cast<detail::locker_unlocker_base *>(&m_buf)->lock();
}
~te_lock_guard() {
reinterpret_cast<detail::locker_unlocker_base *>(&m_buf)->unlock();
}
private:
std::aligned_storage<sizeof(detail::locker_unlocker<std::mutex>), alignof(detail::locker_unlocker<std::mutex>)>::type m_buf;
};
我已经检查了性能与标准库的类:
int main() {
constexpr std::size_t num{999999};
{
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
for(size_t i = 0; i < num; ++i) {
std::mutex m;
te_lock_guard l(m);
}
std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << std::endl;
}
{
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
for(size_t i = 0; i < num; ++i) {
std::mutex m;
std::unique_lock<std::mutex> l(m);
}
std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << std::endl;
}
}
将g++与-O3
一起使用时,不会出现统计上显著的性能损失。
发布于 2016-09-09 18:54:31
上C++17..。同时,不需要类型擦除。模板函数参数推导为我们提供了一个简单的助手:
template<class Mutex>
auto make_lock(Mutex& m)
{
return std::unique_lock<Mutex>(m);
}
...
std::mutex m;
std::recursive_mutex m2;
auto lock = make_lock(m);
auto lock2 = make_lock(m2);
https://stackoverflow.com/questions/39407213
复制相似问题