std::lock_guard
- C++ course
- Advanced
- Lesson 21/83
- 5 min
Learn RAII locking with std::lock_guard.
std::lock_guard
std::lock_guard is an RAII wrapper for a mutex. Its constructor calls lock and its destructor calls unlock. When scope ends the lock is released automatically. The syntax is std::lock_guard<std::mutex> lk(m);.
This prevents forgetting to call lock and unlock. Especially when an exception is thrown the lock still releases because the destructor always runs. lock_guard has only a constructor and destructor; it does not support move or copy. It is ideal for simple, safe critical section management.
Exception safety
The main strength of lock_guard is releasing the lock even when an exception is thrown. With m.lock();, a subsequent throw would skip unlock; the lock would stay forever. lock_guard removes this problem.
This is a typical example of RAII (Resource Acquisition Is Initialization). A resource (lock) is tied to an object's lifetime; when the object dies the resource is released automatically. In modern C++ std::unique_ptr, std::fstream and std::lock_guard follow this principle.
Practice lock_guard counter
Declare global int counter = 0; and std::mutex m;. Write void add_once() whose body is std::lock_guard<std::mutex> lk(m); counter++;. In main start two threads, join both, then write std::cout << counter;.
Starter code
#include <iostream>
#include <thread>
#include <mutex>
int counter = 0;
std::mutex m;
// Write the add_once function
int main() {
// Start two threads, wait, print
return 0;
}Sample solution
#include <iostream>
#include <thread>
#include <mutex>
int counter = 0;
std::mutex m;
void add_once() {
std::lock_guard<std::mutex> lk(m);
counter++;
}
int main() {
std::thread t1(add_once);
std::thread t2(add_once);
t1.join();
t2.join();
std::cout << counter;
return 0;
}Expected output
2
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 When does lock_guard release the lock?
- When scope ends Correct answer
- At program end
- When unlock is called explicitly
- When the thread sleeps
Explanation: lock_guard releases the lock via its destructor at scope end.
2 Match each expression to its role
| Term | Meaning |
|---|---|
std::lock_guard<std::mutex> lk(m) |
RAII wrapper |
lk constructor |
Calls lock |
lk destructor |
Calls unlock |
{ ... } |
Scope end |
3 Complete the lock_guard line
void add_once() {
std::____<std::mutex> lk(m);
counter++;
}
void add_once() {
std::lock_guard<std::mutex> lk(m);
counter++;
}
Explanation: std::lock_guard<std::mutex> lk(m); acquires the lock with RAII.