Tại sao std::lock_guard
và std::unique_lock
yêu cầu chỉ định loại khóa làm thông số mẫu?Tại sao không std :: lock_guard/std :: unique_lock sử dụng loại xóa?
Cân nhắc giải pháp thay thế sau. Thứ nhất, trong một không gian tên detail
, có các lớp học kiểu tẩy xoá (một tổ chức phi mẫu lớp cơ sở trừu tượng, và một nguồn gốc lớp mẫu):
#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;
};
}
Bây giờ te_lock_guard
, khóa bảo vệ loại tẩy xoá, chỉ đơn giản là theo vị trí tin tức một đối tượng loại chính xác khi xây dựng (không phân bổ bộ nhớ động):
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;
};
tôi đã kiểm tra việc thực hiện so với các lớp học thư viện chuẩn của:
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;
}
}
Sử dụng g ++ với -O3
, không có tổn thất hiệu năng đáng kể về mặt thống kê.
'có ý nghĩa thống kê' đối với bạn là gì? Việc thực hiện bản địa có vẻ nhanh hơn sau khi chạy nó 4-5 lần. Vì vậy, không chắc chắn những gì bạn thấy là không đáng kể. Và tại sao chọn triển khai mặc định chậm hơn so với giải pháp thay thế hiện tại? Câu hỏi chính nó là khá interessting mặc dù. Một người nào đó đã đo một giải pháp thay thế. – Hayt
Nếu bạn thực sự quá thất vọng vì phải nhập lại tên loại, bạn có thể sử dụng mẫu hàm: 'auto && lock = guard_me (mx);' ([Demo] (https://ideone.com/ysxJEz) .) –
@Hayt Điều tôi muốn nói là một bài kiểm tra hoán vị thống kê đã không bác bỏ giả thuyết rằng chúng đến từ cùng một phân bố. Theo tôi, sự thay thế phức tạp thực sự đôi khi nhanh hơn, tình cờ. Xử lý số liệu thống kê, tôi cố gắng tránh những tuyên bố mạnh mẽ như "chúng chạy cùng tốc độ". –