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_lockadalah versi yang sangat unggul lock_guardyang 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_guardmasih 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_lockkonstruktor variadic mengambil lebih dari satu mutex. Hal ini memungkinkan untuk mengunci beberapa mutex dengan cara menghindari kebuntuan seolah-olah std::lockdigunakan.
{
// 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::lockseperti yang dijelaskan jawaban ini .
Penambahan kunci ruang lingkup membuat ini lebih mudah digunakan dan menghindari kesalahan terkait. Anda dapat menganggap std::lock_guardtidak berlaku lagi. Kasus argumen tunggal std::scoped_lockdapat diimplementasikan sebagai spesialisasi dan Anda tidak perlu takut tentang kemungkinan masalah kinerja.
GCC 7 sudah memiliki dukungan std::scoped_lockyang 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_guardtidak berlaku lagi.
Untuk kasus umum di mana seseorang perlu mengunci tepat satu mutex, std::lock_guardmemiliki 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_guarddigunakan 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_lockjika Anda perlu membuka kunci dalam cakupan blok (yang mencakup penggunaan dengan a condition_variable).
Saran ini tidak menyiratkan bahwa scoped_lockharus didesain ulang untuk tidak menerima 0 mutex. Terdapat kasus penggunaan yang valid di mana diinginkan untuk scoped_lockmenerima paket parameter template variadic yang mungkin kosong. Dan kotak kosong seharusnya tidak mengunci apapun.
Dan itulah mengapa lock_guardtidak 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_locksarana bahwa sebagian besar kasus di mana Anda akan menggunakanstd::locksebelum c ++ 17 sekarang dapat ditulis menggunakanstd::scoped_lock, dengan potensi kesalahan yang lebih kecil, yang hanya bisa menjadi hal yang baik!