In C ++ 17 wurde eine neue Sperrklasse namens eingeführt std::scoped_lock.
Aus der Dokumentation geht hervor, dass es der bereits vorhandenen std::lock_guardKlasse ähnelt .
Was ist der Unterschied und wann sollte ich es verwenden?
In C ++ 17 wurde eine neue Sperrklasse namens eingeführt std::scoped_lock.
Aus der Dokumentation geht hervor, dass es der bereits vorhandenen std::lock_guardKlasse ähnelt .
Was ist der Unterschied und wann sollte ich es verwenden?
Antworten:
Dies scoped_lockist eine streng überlegene Version lock_guard, die eine beliebige Anzahl von Mutexen gleichzeitig sperrt (unter Verwendung des gleichen Deadlock-Vermeidungsalgorithmus wie std::lock). In neuem Code sollten Sie immer nur verwenden scoped_lock.
Der einzige Grund, der lock_guardnoch besteht, ist die Kompatibilität. Es konnte nicht einfach gelöscht werden, da es im aktuellen Code verwendet wird. Darüber hinaus erwies es sich als unerwünscht, seine Definition zu ändern (von unär zu variadisch), da dies auch eine beobachtbare und damit brechende Änderung ist (jedoch aus etwas technischen Gründen).
lock_guard. Aber es macht die Wachklassen sicherlich ein bisschen einfacher zu benutzen.
Der einzige und wichtige Unterschied besteht darin, dass std::scoped_lockein variadischer Konstruktor mehr als einen Mutex verwendet. Dies ermöglicht es, mehrere Mutexe in einem Deadlock zu sperren und so zu vermeiden, als ob std::locksie verwendet würden.
{
// safely locked as if using std::lock
std::scoped_lock<std::mutex, std::mutex> lock(mutex1, mutex2);
}
Zuvor mussten Sie ein wenig tanzen, um mehrere Mutexe auf sichere Weise zu sperren, indem Sie diese Antwortstd::lock wie erläutert verwenden .
Das Hinzufügen einer Oszilloskopsperre erleichtert die Verwendung und vermeidet die damit verbundenen Fehler. Sie können als std::lock_guardveraltet betrachten. Der Einzelargumentfall vonstd::scoped_lock kann als Spezialisierung implementiert werden, sodass Sie sich nicht vor möglichen Leistungsproblemen fürchten müssen.
GCC 7 hat bereits Unterstützung, std::scoped_lockdie hier zu sehen ist .
Weitere Informationen finden Sie im Standardpapier
scoped_lock lk; // locks all mutexes in scope. LGTM.
scoped_lock lk;ist die neue Abkürzung für scoped_lock<> lk;. Es gibt keine Mutexe. Du hast also recht. ;-)
Späte Antwort und meistens als Antwort auf:
Sie können als
std::lock_guardveraltet betrachten.
Für den allgemeinen Fall, dass man genau einen Mutex sperren muss, std::lock_guardgibt es eine API, die etwas sicherer zu verwenden ist als scoped_lock.
Beispielsweise:
{
std::scoped_lock lock; // protect this block
...
}
Das obige Snippet ist wahrscheinlich ein versehentlicher Laufzeitfehler, da es kompiliert und dann absolut nichts tut. Der Codierer meinte wahrscheinlich:
{
std::scoped_lock lock{mut}; // protect this block
...
}
Jetzt wird es gesperrt / entsperrt mut.
Wenn lock_guardstattdessen in den beiden obigen Beispielen verwendet wurde, ist das erste Beispiel ein Kompilierungsfehler anstelle eines Laufzeitfehlers, und das zweite Beispiel hat die gleiche Funktionalität wie die verwendete Version scoped_lock.
Mein Rat ist also, das einfachste Werkzeug für den Job zu verwenden:
lock_guard Wenn Sie genau 1 Mutex für einen gesamten Bereich sperren müssen.
scoped_lock Wenn Sie eine Anzahl von Mutexen sperren müssen, ist dies nicht genau 1.
unique_lockwenn Sie im Rahmen des Blocks entsperren müssen (einschließlich der Verwendung mit a condition_variable).
Dieser Ratschlag bedeutet nicht , dass er scoped_lockneu gestaltet werden sollte, um keine 0 Mutexe zu akzeptieren. Es gibt gültige Anwendungsfälle, in denen es wünschenswert ist scoped_lock, variable Vorlagenparameterpakete zu akzeptieren, die möglicherweise leer sind. Und der leere Koffer sollte nichts verriegeln.
Und deshalb lock_guardist es nicht veraltet. scoped_lock und unique_lock mag eine Obermenge der Funktionalität von sein lock_guard, aber diese Tatsache ist ein zweischneidiges Schwert. Manchmal ist es genauso wichtig, was ein Typ nicht kann (in diesem Fall Standardkonstrukt).
Hier ist ein Beispiel und ein Zitat aus 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);
}
Das Vorhandensein von
std::scoped_lockbedeutet, dass die meisten Fälle, die Siestd::lockvor c ++ 17 verwendet hätten, jetztstd::scoped_lockmit weniger Fehlerpotential geschrieben werden können, was nur eine gute Sache sein kann!