C ++ 17 memperkenalkan kelas kunci baru yang disebut std::scoped_lock
.
Dilihat dari dokumentasinya sepertinya kelas yang sudah ada std::lock_guard
.
Apa bedanya dan kapan saya harus menggunakannya?
sumber
C ++ 17 memperkenalkan kelas kunci baru yang disebut std::scoped_lock
.
Dilihat dari dokumentasinya sepertinya kelas yang sudah ada std::lock_guard
.
Apa bedanya dan kapan saya harus menggunakannya?
Ini scoped_lock
adalah versi yang sangat unggul lock_guard
yang mengunci sejumlah mutex sekaligus (menggunakan algoritme penghindaran kebuntuan yang sama seperti std::lock
). Dalam kode baru, Anda hanya boleh menggunakan scoped_lock
.
Satu-satunya alasan lock_guard
masih ada adalah untuk kompatibilitas. Itu tidak bisa dihapus begitu saja, karena digunakan dalam kode saat ini. Selain itu, terbukti tidak diinginkan untuk mengubah definisinya (dari unary ke variadic), karena itu juga dapat diamati, dan karenanya melanggar, perubahan (tetapi untuk alasan yang agak teknis).
lock_guard
. Tapi tentu saja membuat kelas penjaga sedikit lebih mudah digunakan.Perbedaan tunggal dan penting adalah bahwa
std::scoped_lock
konstruktor variadic mengambil lebih dari satu mutex. Hal ini memungkinkan untuk mengunci beberapa mutex dengan cara menghindari kebuntuan seolah-olahstd::lock
digunakan.{ // safely locked as if using std::lock std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2); }
Sebelumnya Anda harus melakukan sedikit tarian untuk mengunci beberapa mutex dengan cara yang aman menggunakan
std::lock
seperti yang dijelaskan jawaban ini .Penambahan kunci ruang lingkup membuat ini lebih mudah digunakan dan menghindari kesalahan terkait. Anda dapat menganggap
std::lock_guard
tidak berlaku lagi. Kasus argumen tunggalstd::scoped_lock
dapat diimplementasikan sebagai spesialisasi dan Anda tidak perlu takut tentang kemungkinan masalah kinerja.GCC 7 sudah memiliki dukungan
std::scoped_lock
yang bisa dilihat di sini .Untuk informasi lebih lanjut Anda mungkin ingin membaca kertas standar
sumber
scoped_lock lk; // locks all mutexes in scope
. LGTM.scoped_lock lk;
adalah singkatan baru untukscoped_lock<> lk;
. Ada yang tidak ada mutexes. Jadi kamu benar. ;-)Jawaban terlambat, dan sebagian besar menanggapi:
Untuk kasus umum di mana seseorang perlu mengunci tepat satu mutex,
std::lock_guard
memiliki API yang sedikit lebih aman untuk digunakan daripadascoped_lock
.Sebagai contoh:
{ std::scoped_lock lock; // protect this block ... }
Cuplikan di atas kemungkinan besar merupakan kesalahan waktu proses yang tidak disengaja karena ia mengkompilasi dan kemudian tidak melakukan apa pun. Pembuat kode itu mungkin berarti:
{ std::scoped_lock lock{mut}; // protect this block ... }
Sekarang mengunci / membuka kunci
mut
.Jika
lock_guard
digunakan dalam dua contoh di atas, contoh pertama adalah kesalahan waktu kompilasi dan bukan kesalahan waktu proses, dan contoh kedua memiliki fungsionalitas yang identik dengan versi yang digunakanscoped_lock
.Jadi saran saya adalah menggunakan alat paling sederhana untuk pekerjaan itu:
lock_guard
jika Anda perlu mengunci tepat 1 mutex untuk seluruh cakupan.scoped_lock
jika Anda perlu mengunci sejumlah mutex yang tidak persis 1.unique_lock
jika Anda perlu membuka kunci dalam cakupan blok (yang mencakup penggunaan dengan acondition_variable
).Saran ini tidak menyiratkan bahwa
scoped_lock
harus didesain ulang untuk tidak menerima 0 mutex. Terdapat kasus penggunaan yang valid di mana diinginkan untukscoped_lock
menerima paket parameter template variadic yang mungkin kosong. Dan kotak kosong seharusnya tidak mengunci apapun.Dan itulah mengapa
lock_guard
tidak ditinggalkan.scoped_lock
danunique_lock
mungkin merupakan superset dari fungsionalitaslock_guard
, tetapi fakta itu adalah pedang bermata dua. Terkadang sama pentingnya dengan apa yang tidak akan dilakukan oleh suatu tipe (konstruksi default dalam kasus ini).sumber
Berikut adalah contoh dan kutipan dari C ++ Concurrency in Action :
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); }
vs.
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); }
sumber