Perbedaannya adalah bahwa Anda dapat mengunci dan membuka kunci a std::unique_lock
. std::lock_guard
akan dikunci hanya sekali pada konstruksi dan tidak terkunci pada kehancuran.
Jadi untuk kasus penggunaan B Anda pasti membutuhkan std::unique_lock
variabel kondisi. Dalam kasus A itu tergantung apakah Anda perlu mengunci kembali penjaga.
std::unique_lock
memiliki fitur lain yang memungkinkannya misalnya: dibangun tanpa mengunci mutex segera tetapi untuk membangun pembungkus RAII (lihat di sini ).
std::lock_guard
juga menyediakan pembungkus RAII yang nyaman, tetapi tidak dapat mengunci beberapa mutex dengan aman. Ini dapat digunakan ketika Anda membutuhkan pembungkus untuk lingkup terbatas, misalnya: fungsi anggota:
class MyClass{
std::mutex my_mutex;
void member_foo() {
std::lock_guard<mutex_type> lock(this->my_mutex);
/*
block of code which needs mutual exclusion (e.g. open the same
file in multiple threads).
*/
//mutex is automatically released when lock goes out of scope
};
Untuk mengklarifikasi pertanyaan dengan chmike, secara default std::lock_guard
dan std::unique_lock
sama. Jadi dalam kasus di atas, Anda bisa menggantinya std::lock_guard
dengan std::unique_lock
. Namun, std::unique_lock
mungkin sedikit lebih mahal.
Perhatikan bahwa hari ini seseorang harus menggunakan std::scoped_lock
sebagai ganti std::lock_guard
.
std::lock_guard
cukup untuk kasus A Anda, maka Anda harus menggunakannya. Tidak hanya menghindari overhead yang tidak perlu tetapi juga menunjukkan niat kepada pembaca bahwa Anda tidak akan pernah membuka kunci penjaga ini.unique_lock
kemungkinan akan dikerdilkan oleh biaya untuk benar-benar mengunci dan membuka kunci mutex (jika kompiler tidak mengoptimalkan overhead yang jauh, yang mungkin dilakukan).So for usecase B you definitely need a std::unique_lock for the condition variable
- ya tetapi hanya di utas yangcv.wait()
s, karena metode itu secara atom melepaskan mutex. Di utas lain tempat Anda memperbarui variabel yang dibagi-pakai (s) dan kemudian meneleponcv.notify_one()
,lock_guard
cukup sederhana untuk mengunci mutex dalam-lingkup ... kecuali Anda melakukan sesuatu yang lebih rumit yang tidak dapat saya bayangkan! mis. en.cppreference.com/w/cpp/thread/condition_variable - berfungsi untuk saya :)lock_guard
dan halunique_lock
yang hampir sama;lock_guard
adalah versi terbatas dengan antarmuka terbatas.A
lock_guard
selalu memegang kunci dari konstruksi hingga kehancurannya. Aunique_lock
dapat dibuat tanpa segera mengunci, dapat membuka pada titik mana pun dalam keberadaannya, dan dapat mentransfer kepemilikan kunci dari satu contoh ke yang lain.Jadi Anda selalu menggunakan
lock_guard
, kecuali jika Anda membutuhkan kemampuanunique_lock
. SEBUAHcondition_variable
membutuhkanunique_lock
.sumber
A condition_variable needs a unique_lock.
- ya tetapi hanya diwait()
sisi ing, seperti yang dijelaskan dalam komentar saya ke inf.Gunakan
lock_guard
kecuali Anda harus dapat secara manualunlock
menggunakan mutex di antaranya tanpa merusaknyalock
.Secara khusus,
condition_variable
membuka kunci mutunya ketika akan tidur saat panggilan kewait
. Itu sebabnya alock_guard
tidak memadai di sini.sumber
lock_guard
dan membuka kuncinya, sehingga melanggar sementara kelas invarian penjaga. Meskipun ini terjadi tidak terlihat oleh pengguna, saya akan mempertimbangkan bahwa alasan yang sah untuk tidak mengizinkan penggunaanlock_guard
dalam kasus ini.lock_guard
tidak memungkinkan mengambil mutex yang mendasarinya sama sekali. Ini adalah batasan yang disengaja untuk memungkinkan penalaran yang lebih sederhana tentang kode yang digunakanlock_guard
sebagai kebalikan dari kode yang menggunakan aunique_lock
. Satu-satunya cara untuk mencapai apa yang Anda tanyakan adalah dengan secara sengaja memecah enkapsulasilock_guard
kelas dan mengekspos implementasinya ke kelas yang berbeda (dalam hal inicondition_variable
). Ini adalah harga yang sulit untuk dibayar untuk keuntungan yang dipertanyakan dari pengguna variabel kondisi tidak harus mengingat perbedaan antara kedua jenis kunci.condition_variable_any.wait
akan berhasil denganlock_guard
? Standar ini mengharuskan jenis Kunci yang disediakan untuk memenuhiBasicLockable
persyaratan (§30.5.2), yanglock_guard
tidak. Hanya mutex yang mendasarinya, tetapi karena alasan yang saya tunjukkan sebelumnya antarmukalock_guard
tidak menyediakan akses ke mutex.Ada beberapa hal umum antara
lock_guard
danunique_lock
dan perbedaan tertentu.Tetapi dalam konteks pertanyaan yang diajukan, kompiler tidak mengizinkan penggunaan a
lock_guard
kombinasi dengan variabel kondisi, karena ketika sebuah thread panggilan menunggu variabel kondisi, mutex akan dibuka secara otomatis dan ketika thread / utas lainnya memberi tahu dan utas saat ini dipanggil (keluar dari menunggu), kunci diperoleh kembali.Fenomena ini bertentangan dengan prinsip
lock_guard
.lock_guard
dapat dibangun hanya sekali dan dihancurkan hanya sekali.Karenanya
lock_guard
tidak dapat digunakan dalam kombinasi dengan variabel kondisi, tetapi aunique_lock
dapat (karenaunique_lock
dapat dikunci dan dibuka beberapa kali).sumber
he compiler does not allow using a lock_guard in combination with a condition variable
Ini salah. Ini tentu saja memungkinkan dan bekerja dengan sempurna denganlock_guard
dukungannotify()
. Hanyawait()
sisi int memerlukan aunique_lock
, karenawait()
harus melepaskan kunci saat memeriksa kondisi.Mereka bukan mutex yang benar-benar sama,
lock_guard<muType>
memiliki hampir sama denganstd::mutex
, dengan perbedaan bahwa itu seumur hidup berakhir pada akhir lingkup (D-tor disebut) sehingga definisi yang jelas tentang dua mutex ini:Dan
Berikut ini contoh penerapannya:
Dalam contoh ini, saya menggunakan
unique_lock<muType>
dengancondition variable
sumber
Seperti yang telah disebutkan oleh orang lain, std :: unique_lock melacak status terkunci dari mutex, sehingga Anda dapat menunda penguncian sampai setelah pembangunan kunci, dan membuka sebelum kerusakan kunci. std :: lock_guard tidak mengizinkan ini.
Tampaknya tidak ada alasan mengapa fungsi menunggu std :: condition_variable tidak boleh mengambil lock_guard serta unique_lock, karena setiap kali menunggu berakhir (untuk alasan apa pun) mutex secara otomatis diperoleh kembali sehingga tidak akan menyebabkan pelanggaran semantik. Namun menurut standar, untuk menggunakan std :: lock_guard dengan variabel kondisi, Anda harus menggunakan std :: condition_variable_any alih-alih std :: condition_variable.
Sunting : dihapus "Menggunakan antarmuka pthreads std :: condition_variable dan std :: condition_variable_any harus identik". Saat melihat implementasi gcc:
sumber