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?
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?
Jawaban:
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-olah std::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 tunggal std::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
scoped_lock lk; // locks all mutexes in scope
. LGTM.
scoped_lock lk;
adalah singkatan baru untuk scoped_lock<> lk;
. Ada yang tidak ada mutexes. Jadi kamu benar. ;-)
Jawaban terlambat, dan sebagian besar menanggapi:
Anda dapat menganggap
std::lock_guard
tidak berlaku lagi.
Untuk kasus umum di mana seseorang perlu mengunci tepat satu mutex, std::lock_guard
memiliki API yang sedikit lebih aman untuk digunakan daripada scoped_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 digunakan scoped_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 a condition_variable
).
Saran ini tidak menyiratkan bahwa scoped_lock
harus didesain ulang untuk tidak menerima 0 mutex. Terdapat kasus penggunaan yang valid di mana diinginkan untuk scoped_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
dan unique_lock
mungkin merupakan superset dari fungsionalitas lock_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).
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);
}
Adanya
std::scoped_lock
sarana bahwa sebagian besar kasus di mana Anda akan menggunakanstd::lock
sebelum c ++ 17 sekarang dapat ditulis menggunakanstd::scoped_lock
, dengan potensi kesalahan yang lebih kecil, yang hanya bisa menjadi hal yang baik!