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_guard
lớ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_guard
lớ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_lock
là 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_guard
vẫ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_lock
có 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::lock
giả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_guard
không dùng nữa. Trường hợp đối số duy nhất std::scoped_lock
có 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_lock
có 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_guard
khô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_guard
có 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_lock
nế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_lock
nê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_lock
chấ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_guard
khô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_lock
phương tiện có nghĩa là hầu hết các trường hợp mà bạn đã sử dụngstd::lock
trướ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!