C ++ 17 đã giới thiệu một lớp khóa mới được gọi là std::scoped_lock.
Đánh giá từ tài liệu này có vẻ tương tự như std::lock_guardlớp đã có .
Sự khác biệt là gì và khi nào tôi nên sử dụng nó?
C ++ 17 đã giới thiệu một lớp khóa mới được gọi là std::scoped_lock.
Đánh giá từ tài liệu này có vẻ tương tự như std::lock_guardlớp đã có .
Sự khác biệt là gì và khi nào tôi nên sử dụng nó?
Câu trả lời:
Đây scoped_locklà một phiên bản ưu việt hoàn toàn lock_guard, khóa một số lượng các trường hợp tùy ý cùng một lúc (sử dụng cùng một thuật toán tránh bế tắc như std::lock). Trong mã mới, bạn chỉ nên sử dụng scoped_lock.
Lý do duy nhất lock_guardvẫn tồn tại là để tương thích. Nó không thể bị xóa, bởi vì nó được sử dụng trong mã hiện tại. Hơn nữa, nó đã tỏ ra không mong muốn thay đổi định nghĩa của nó (từ unary sang matrixdic), bởi vì đó cũng là một điều có thể quan sát được, và do đó phá vỡ, thay đổi (nhưng vì lý do kỹ thuật nào đó).
lock_guard. Nhưng nó chắc chắn làm cho các lớp bảo vệ dễ sử dụng hơn một chút.
Sự khác biệt duy nhất và quan trọng là std::scoped_lockcó một hàm tạo dao động lấy nhiều hơn một mutex. Điều này cho phép khóa nhiều mutexes trong một cách tránh bế tắc như thể std::lockđược sử dụng.
{
// safely locked as if using std::lock
std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2);
}
Trước đây bạn phải thực hiện một điệu nhảy nhỏ để khóa nhiều đột biến một cách an toàn bằng cách std::lockgiải thích câu trả lời này .
Việc bổ sung khóa phạm vi giúp việc này dễ sử dụng hơn và tránh các lỗi liên quan. Bạn có thể xem xét std::lock_guardkhông dùng nữa. Trường hợp đối số duy nhất std::scoped_lockcó thể được triển khai như một chuyên môn và do đó bạn không phải lo lắng về các vấn đề hiệu suất có thể xảy ra.
GCC 7 đã có hỗ trợ std::scoped_lockcó thể được nhìn thấy ở đây .
Để biết thêm thông tin bạn có thể muốn đọc giấy tiêu chuẩn
scoped_lock lk; // locks all mutexes in scope. LGTM.
scoped_lock lk;là cách viết tắt mới cho scoped_lock<> lk;. Có là không có mutexes. Vì vậy, bạn đã đúng. ;-)
Câu trả lời muộn và chủ yếu là để đáp lại:
Bạn có thể xem xét
std::lock_guardkhông dùng nữa.
Đối với trường hợp phổ biến là người ta cần khóa chính xác một mutex, std::lock_guardcó API an toàn hơn một chút để sử dụng scoped_lock.
Ví dụ:
{
std::scoped_lock lock; // protect this block
...
}
Đoạn mã trên có thể là một lỗi thời gian chạy ngẫu nhiên vì nó biên dịch và sau đó hoàn toàn không làm gì cả. Các lập trình viên có thể có nghĩa là:
{
std::scoped_lock lock{mut}; // protect this block
...
}
Bây giờ nó khóa / mở khóa mut.
Nếu lock_guardđược sử dụng trong hai ví dụ trên thay vào đó, ví dụ đầu tiên là lỗi thời gian biên dịch thay vì lỗi thời gian chạy và ví dụ thứ hai có chức năng giống hệt như phiên bản sử dụng scoped_lock.
Vì vậy, lời khuyên của tôi là sử dụng công cụ đơn giản nhất cho công việc:
lock_guard nếu bạn cần khóa chính xác 1 mutex cho toàn bộ phạm vi.
scoped_lock nếu bạn cần khóa một số mutexes không chính xác 1.
unique_locknếu bạn cần mở khóa trong phạm vi của khối (bao gồm sử dụng với a condition_variable).
Lời khuyên này không ngụ ý rằng scoped_locknên được thiết kế lại để không chấp nhận 0 mutexes. Có tồn tại các trường hợp sử dụng hợp lệ trong đó mong muốn scoped_lockchấp nhận các gói tham số mẫu có thể bị trống. Và trường hợp trống không nên khóa bất cứ điều gì.
Và đó là lý do tại sao lock_guardkhông được tán thành. scoped_lock và unique_lock có thể là một siêu chức năng của lock_guard, nhưng thực tế đó là con dao hai lưỡi. Đôi khi nó cũng quan trọng như những gì một loại sẽ không làm (cấu trúc mặc định trong trường hợp này).
Dưới đây là một mẫu và trích dẫn từ C ++ đồng thời trong hành động :
friend void swap(X& lhs, X& rhs)
{
if (&lhs == & rhs)
return;
std::lock(lhs.m, rhs.m);
std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);
std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);
swap(lhs.some_detail, rhs.some_detail);
}
so với
friend void swap(X& lhs, X& rhs)
{
if (&lhs == &rhs)
return;
std::scoped_lock guard(lhs.m, rhs.m);
swap(lhs.some_detail, rhs.some_detail);
}
Sự tồn tại của
std::scoped_lockphương tiện có nghĩa là hầu hết các trường hợp mà bạn đã sử dụngstd::locktrước c ++ 17 bây giờ có thể được viết bằng cách sử dụngstd::scoped_lock, với ít khả năng xảy ra lỗi hơn, chỉ có thể là một điều tốt!