1. Vấn đề nó giải quyết
Mutex bảo vệ invariant dùng chung, lock RAII tự nhả an toàn, còn condition variable cho thread ngủ tới khi trạng thái được bảo vệ có thể thỏa predicate. Nó làm ràng buộc quan trọng hiện rõ thay vì bắt người đọc đoán. Bài chỉ giữ phần cốt lõi C++11 vừa đủ cho một ngày tập trung.
2. Kiến thức cần có
Kiến thức Ngày 45, cùng biến, hàm và cách đọc output đã học trước đó.
3. Ý tưởng cốt lõi
Mental model: Mutex bảo vệ invariant dùng chung, lock RAII tự nhả an toàn, còn condition variable cho thread ngủ tới khi trạng thái được bảo vệ có thể thỏa predicate. Hãy xác định giá trị hoặc trạng thái liên quan, ai sở hữu nó và quy tắc tác động lúc compile hay lúc chạy.
4. Cú pháp tối thiểu
std::unique_lock<std::mutex> lock(m); cv.wait(lock, predicate);5. Cách nó hoạt động
Ví dụ tạo dữ liệu nhỏ, cố định và không cần nhập bàn phím.
C++11 hoặc contract thư viện chuẩn áp dụng quy tắc hôm nay.
Chương trình in kết quả quan trọng để đối chiếu với mã nguồn.
6. Lỗi thường gặp
Wait không có predicate là sai vì có thể thức giả; đọc trạng thái dùng chung ngoài mutex có thể tạo data race.
7. Khi nào nên dùng
Nên dùng khi các thread phối hợp quanh trạng thái chung thay vì quay vòng liên tục.
Tránh dùng khi nó che ownership, lifetime, kiểu, thứ tự hoặc chi phí.
8. Ví dụ đơn giản
Producer lưu một giá trị dưới lock rồi notify; consumer wait với predicate và in giá trị đó. File .cpp dùng dữ liệu cố định và không thêm abstraction ngoài chủ đề.
Mã mẫu hoàn chỉnh
Tệp mã nguồn
cpp11/46_mutex_locks_condition_variable/main.cpp
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int main() {
std::mutex mutex;
std::condition_variable ready_cv;
bool ready = false;
int value = 0;
std::thread consumer([&] {
std::unique_lock<std::mutex> lock(mutex);
ready_cv.wait(lock, [&] { return ready; });
std::cout << "value=" << value << '\n';
});
std::thread producer([&] {
{
std::lock_guard<std::mutex> lock(mutex);
value = 42;
ready = true;
}
ready_cv.notify_one();
});
producer.join();
consumer.join();
}
9. Điều cần nhớ
Tính năng nằm trong phạm vi C++11 của lộ trình này.
Hiểu hệ quả về lifetime, ownership, kiểu và thứ tự trước khi dùng.
Compile với cảnh báo và ưu tiên cách viết nhỏ nhất làm quy tắc hiện rõ.
10. Câu hỏi tự kiểm tra
Dễ — Trong
std::unique_lock<std::mutex> lock(m); cv.wait(lock, predicate);, mutex, đối tượng lock và condition variable có vai trò gì? Vì sao cần predicate?Trung bình — Đọc ví dụ nhỏ ở trên. Chương trình sẽ in giá trị hoặc trạng thái nào, và quy tắc nào tạo ra kết quả đó?
Khó — Tìm và giải thích lỗi tinh tế trong tình huống sau: Wait không có predicate là sai vì có thể thức giả; đọc trạng thái dùng chung ngoài mutex có thể tạo data race. Cách sửa nhỏ nhất nhưng an toàn trong C++11 là gì?