Giao diện
Concurrency Fundamentals
🎯 Mục tiêu
🎯 Sau bài thực hành này, bạn sẽ:
- Tạo và quản lý threads an toàn với
std::thread - Sử dụng mutex bảo vệ shared data
- Implement producer-consumer với condition_variable
- Dùng async/future cho tính toán song song
Mô tả bài tập
Concurrency giúp tận dụng CPU multi-core nhưng đi kèm cạm bẫy: data race, deadlock. Bài tập xây dựng nền tảng concurrency vững chắc.
Yêu cầu
Bài 1: Parallel Sum với Threads
Chia mảng thành 4 phần, mỗi thread tính tổng một phần.
cpp
void partialSum(const std::vector<int>& data,
size_t start, size_t end,
std::vector<long long>& results, size_t index) {
// TODO: Tính tổng data[start..end) vào results[index]
}
int main() {
std::vector<int> data(1000000);
std::iota(data.begin(), data.end(), 1);
// TODO: Tạo 4 threads, join, cộng kết quả → 500000500000
}Bài 2: Thread-safe Counter với Mutex
cpp
class SafeCounter {
int count = 0;
std::mutex mtx;
public:
void increment() { /* TODO: lock_guard + ++count */ }
int getCount() const { /* TODO: lock_guard + return */ }
};
// 10 threads × 10000 increments = 100000Bài 3: Producer-Consumer
Implement bounded buffer với condition_variable.
cpp
template <typename T>
class BoundedBuffer {
std::queue<T> buffer;
size_t maxSize;
std::mutex mtx;
std::condition_variable notFull, notEmpty;
public:
explicit BoundedBuffer(size_t size) : maxSize(size) {}
void produce(const T& item); // đợi nếu đầy
T consume(); // đợi nếu rỗng
};Gợi ý
Gợi ý Bài 1
Tạo thread: threads.emplace_back(partialSum, std::cref(data), start, end, std::ref(results), i). Nhớ join tất cả.
Gợi ý Bài 3
produce: unique_lock + notFull.wait(lock, []{return size < max}) + push + notEmpty.notify_one().
Lời giải tham khảo
Xem lời giải
cpp
void partialSum(const std::vector<int>& data,
size_t start, size_t end,
std::vector<long long>& results, size_t index) {
results[index] = std::accumulate(data.begin() + start, data.begin() + end, 0LL);
}
void SafeCounter::increment() {
std::lock_guard<std::mutex> lock(mtx);
++count;
}
template <typename T>
void BoundedBuffer<T>::produce(const T& item) {
std::unique_lock<std::mutex> lock(mtx);
notFull.wait(lock, [this] { return buffer.size() < maxSize; });
buffer.push(item);
notEmpty.notify_one();
}
template <typename T>
T BoundedBuffer<T>::consume() {
std::unique_lock<std::mutex> lock(mtx);
notEmpty.wait(lock, [this] { return !buffer.empty(); });
T item = buffer.front();
buffer.pop();
notFull.notify_one();
return item;
}