Skip to content

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 = 100000

Bà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;
}