std :: lock_guard veya std :: scoped_lock?


Yanıtlar:


125

Bu scoped_lock, kesinlikle lock_guardaynı anda muteks sayısını kilitleyen, aynı kilitlenme önleme algoritmasını kullanarak kesin olarak üstün bir versiyonudur std::lock. Yeni kodda, yalnızca hiç kullanmamalısınız scoped_lock.

lock_guardHalen var olmanın tek nedeni uyumluluktur. Geçerli kodda kullanıldığı için sadece silinemedi. Dahası, tanımını değiştirmek (istenmeyenlerden varadiklere) istenmeyen bir durumdu, çünkü bu da gözlemlenebilir ve dolayısıyla kırıcı bir değişikliktir (ancak bir şekilde teknik nedenlerden dolayı).


8
Ayrıca, sınıf şablonu argümanı kesinti sayesinde, kilitlenebilir türleri listelemenize bile gerek yoktur.
Nicol Bolas

3
@NicolBolas: Bu doğru, ama aynı zamanda geçerlidir lock_guard. Ancak koruma sınıflarının kullanımını biraz daha kolaylaştırıyor.
Kerrek SB

6
scoped_lock sadece C ++ 17'dir
Shital Shah

1
C ++ 17 olduğu için uyumluluk, varlığının özellikle iyi bir nedenidir. Ayrıca, mürekkep hala bu standarttan kururken "kesinlikle kullanmalısın" mutlakçı iddiasına şiddetle katılmıyorum.
Paul Childs

88

Tek ve önemli fark, std::scoped_lockbirden fazla muteksi alan değişken bir kurucuya sahip olmasıdır. Bu, sanki std::lockkullanılmış gibi kaçınarak birden fazla muteksi kilitlenerek kilitlemeye izin verir .

{
    // safely locked as if using std::lock
    std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2);     
}

Daha önce bu cevabıstd::lock açıkladığı gibi birden fazla muteksi güvenli bir şekilde kilitlemek için küçük bir dans yapmak zorundaydınız .

Kapsam kilidinin eklenmesi bunu kullanmayı kolaylaştırır ve ilgili hataları önler. Kullanımdan std::lock_guardkaldırılmış olarak değerlendirebilirsiniz. Tek argüman örneği std::scoped_lockbir uzmanlık alanı olarak uygulanabilir ve bu nedenle olası performans sorunlarından korkmanıza gerek kalmaz.

GCC 7 zaten buradastd::scoped_lock görülebilen desteğe sahip .

Daha fazla bilgi için standart kağıdı okumak isteyebilirsiniz


9
Sadece 10 dakika sonra kendi sorunuzu yanıtladı. Gerçekten bilmiyor muydun?
Walter


3
Komitede gündeme getirdiğimde, cevap "hiçbir şey" değildi. Bazı algoritmaların dejenere olması bu doğru şeydir. Ya da bir şeyi kilitlemeyi amaçladıklarında yeterince kişinin yanlışlıkla hiçbir şeyi kilitlememesi yaygın bir sorun olabilir. Gerçekten emin değilim.
Howard Hinnant

3
@HowardHinnant: scoped_lock lk; // locks all mutexes in scope. LGTM.
Kerrek SB

2
@KerrekSB: scoped_lock lk;için yeni kestirme yol scoped_lock<> lk;. Orada olan hiçbir muteksler. Yani haklısın. ;-)
Howard Hinnant

26

Geç cevap ve çoğunlukla aşağıdakilere yanıt olarak:

Kullanımdan std::lock_guardkaldırılmış olarak değerlendirebilirsiniz.

Bir kişinin tam olarak bir muteksi kilitlemesi gerektiği genel durum std::lock_guardiçin, kullanmaktan biraz daha güvenli bir API'ye sahiptir scoped_lock.

Örneğin:

{
   std::scoped_lock lock; // protect this block
   ...
}

Yukarıdaki snippet muhtemelen yanlışlıkla bir çalışma zamanı hatasıdır çünkü derler ve sonra kesinlikle hiçbir şey yapmaz. Kodlayıcı muhtemelen:

{
   std::scoped_lock lock{mut}; // protect this block
   ...
}

Şimdi kilitleniyor / kilidini açıyor mut.

Eğer lock_guardbunun yerine, yukarıdaki iki örnekte kullanılmıştır, ilk örnek yerine çalıştırma hatası bir derleme hatası olduğu, ve ikinci bir örneği kullanımları versiyonu olarak aynı özelliğe sahip scoped_lock.

Bu yüzden tavsiyem iş için en basit aracı kullanmaktır:

  1. lock_guard tüm kapsam için tam olarak 1 muteksi kilitlemeniz gerekiyorsa.

  2. scoped_lock tam olarak olmayan bir dizi muteksi kilitlemeniz gerekiyorsa 1.

  3. unique_lockblok kapsamında kilidini açmanız gerekiyorsa (a ile birlikte kullanım içerir condition_variable).

Bu tavsiye etmez değil ima scoped_lock0 muteksleri kabul etmeyecek şekilde yeniden dizayn edilmelidir. scoped_lockBoş olabilecek değişken şablon parametre paketlerini kabul etmenin istendiği geçerli kullanım örnekleri vardır . Ve boş durumda olmalıdır değil bir şey kilitleyin.

İşte bu yüzden lock_guarditiraz edilmiyor. scoped_lock ve unique_lock işlevselliğinin bir üst kümesi olabilir lock_guard, ama bu gerçek iki ucu keskin bir kılıçtır. Bazen bir türün ne yapmayacağı da önemlidir (bu durumda varsayılan yapı).


13

İşte C ++ Concurrency in Action'dan bir örnek ve alıntı :

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);
}

Araçların varlığı, c ++ 17'den önce kullanacağınız std::scoped_lockçoğu vakanın , sadece daha iyi bir şey olabilen hatalar için daha az potansiyel std::lockkullanarak kullanılarak yazılabileceği anlamına gelir std::scoped_lock!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.