Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lesson 4 — Concurrency with Threads & Channels


🎯 Learning Objectives

  • Hiểu cách tạo và quản lý thread trong Rust.
  • Biết dùng mpsc::channel để giao tiếp giữa các thread.

✅ Explanation & Key Concepts

Thread Basics

std::thread::spawn tạo một thread mới để chạy closure. Nếu closure mượn dữ liệu, cần dùng move để chuyển ownership.

Channels

std::sync::mpsc (multi-producer, single-consumer) cho phép gửi message từ nhiều thread đến một receiver duy nhất.

Safety

Ownership + borrowing đảm bảo dữ liệu được chia sẻ giữa các thread an toàn, compiler ngăn data race.


💻 Example Implementation

Cargo.toml

[package]
name = "lesson04_concurrency"
version = "0.1.0"
edition = "2024"

src/main.rs


use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let (tx, rx) = mpsc::channel();

    // Spawn a worker thread
    let handle = thread::spawn(move || {
        for i in 1..=5 {
            let msg = format!("Worker says: Hi, dp — {}", i);
            tx.send(msg).unwrap();
            thread::sleep(Duration::from_millis(500));
        }
    });

    // Main thread receives messages
    // take(5): only receives the first 5 messages from the channel then stops
    for received in rx.iter().take(5) {
        println!("Main got: {received}");
    }

    // join(): ensures the child thread finished before the main thread exits
    handle.join().unwrap();
}

🛠️ Hands-on Exercises

  1. Basic: Tạo 2 thread, mỗi thread gửi 5 message về main. In tất cả message ra màn hình.
  2. Intermediate: Viết hàm spawn_logger(rx: Receiver<String>) chạy trong thread riêng, chỉ nhận và in log. Main gửi log qua channel.
  3. Challenge: Xây worker pool 4 thread xử lý số nguyên từ 1..20, mỗi worker tính bình phương rồi gửi kết quả về main để in.

🐞 Common Pitfalls & Debugging Tips

Common Pitfalls

  • Quên move khi spawn closure → borrow checker báo lỗi.
  • Dùng channel bị drop sớm → sender/receiver closed, gây panic khi send.
  • Block main thread vô hạn khi không join hoặc không giới hạn số message.

❓ Q&A — Common Questions

Q1. Rust đảm bảo an toàn bộ nhớ khi multi-thread bằng cách nào?

  • Nhờ hệ thống ownership/borrowing + trait Send/Sync. Chỉ các kiểu an toàn mới được chia sẻ/transferred giữa threads. Borrow checker ngăn data race ở compile-time: không cho vừa mutable-borrow vừa shared-borrow trùng thời gian.

Q2. move closure trong thread::spawn dùng để làm gì?

  • move chuyển ownership (hoặc copy/clone nếu phù hợp) các biến môi trường vào closure chạy trên thread mới. Điều này tránh việc thread mới mượn dữ liệu đã hết thời (dropped) ở thread cũ.

Q3. Khi nào dùng channel (mpsc) thay vì Arc<Mutex<T>)?

  • Channel: phù hợp mô hình message passing (không chia sẻ trạng thái), pipeline/queue, nhiều producer một consumer. Tránh lock-contention, tách biệt luồng dữ liệu.
  • Arc<Mutex<T>: phù hợp khi nhiều thread cần truy cập/chỉnh cùng một cấu trúc dữ liệu dùng chung. Đơn giản nhưng có chi phí lock và dễ deadlock nếu thiết kế kém. Gợi ý: ưu tiên message passing trước; chỉ dùng shared-state + lock khi thực sự cần.

🔄 Migration Notes (Rust 2024+)

Migration Guidance

  • Concurrency core (thread, mpsc) vẫn ổn định nhiều năm.
  • Edition 2024 cải thiện ergonomics khi capture biến vào closure với move.
  • Với task nặng I/O, xem xét async (tokio) nhưng thread/channel luôn là nền tảng.

📚 References


📖 Glossary of Terms

Key Terms

  • Thread: luồng thực thi độc lập.
  • Channel (mpsc): cơ chế gửi nhận message giữa thread.
  • move closure: chuyển ownership vào thread.
  • Join handle: giá trị trả về từ thread::spawn, dùng để join().

🌿 Wisdom Note

Đạo Đức Kinh — Chương 42

Vạn vật sinh ư hữu, hữu sinh ư vô.

All things are born from being. Being is born from non-being.

Concurrency cũng vậy: từ một main thread (một “hữu”), ta sinh ra nhiều worker thread (vạn vật), cùng hợp tác nhưng không phá vỡ an toàn bộ nhớ.