Hiểu đúng về Thread, Process, Deadlock và Race Condition trong lập trình song song

06 tháng 4, 2026·5 phút đọc

Bài viết phân tích sự khác biệt giữa Thread và Process, cũng như các khái niệm cốt lõi về đồng thời (concurrency) và song song (parallelism). Chúng ta sẽ cùng đi sâu vào các thách thức như race condition và deadlock khi phát triển hệ thống đa luồng.

Hiểu đúng về Thread, Process, Deadlock và Race Condition trong lập trình song song

Bạn có chắc mình hiểu rõ sự khác biệt giữa ThreadProcess không? Đây là một câu hỏi kinh điển thường xuất hiện trong các bài kiểm tra kiến thức dành cho sinh viên ngành công nghệ thông tin.

AnalogiesAnalogies

Nhiều người thường ví von: "Nếu Process là nước thì Thread là ống hút". Tuy nhiên, tôi cho rằng cách ví này chưa chính xác về mặt cấu trúc. Thực tế, Process chứa đựng Thread, chứ không phải ngược lại.

Một cách ví von chính xác hơn là: Process giống như một nhà máy với máy móc và chứng nhận an toàn, còn Thread chính là người vận hành, đơn vị thực thi công việc dựa trên tài nguyên mà nhà máy đó cung cấp.

Từ quy mô nhỏ đến lớn

Hãy tưởng tượng chúng ta xây dựng hệ thống quản lý cho một tiệm bánh nhỏ với trung bình 50 đơn hàng mỗi ngày. Các đơn hàng được ghi vào sổ cái (ledger book) và báo cáo tồn kho được cập nhật hàng ngày. Với khối lượng thấp, việc xử lý tuần tự từng bản ghi là một quyết định tuyệt vời. Nó giúp giảm độ phức tạp của giải pháp và phù hợp với quy mô cầu, cho phép hoàn thành báo cáo cuối ngày chỉ trong vài mili-giây.

Nhưng nếu tiệm bánh đó phát triển thành một chuỗi cửa hàng quốc gia với trung bình 1 triệu đơn hàng mỗi ngày thì sao? Việc xử lý khối lượng dữ liệu khổng lồ đó bằng một Thread duy nhất có thể sẽ mất hàng giờ đồng hồ. Lúc này, việc chia nhỏ xử lý thành nhiều Thread là bắt buộc, dẫn đến việc triển khai các chiến lược về Concurrency (đồng thời) và Parallelism (song song).

Thách thức của đa luồng

Môi trường đa luồng (multi-thread) không chỉ giúp tối ưu hóa thời gian rảnh rỗi trong các môi trường đơn luồng bằng cách chuyển đổi giữa các tác vụ (như có thể thấy trong Event Loop của Node.js), mà còn là yếu tố then chốt để duy trì tính nhất quán trong các giải pháp song song.

Tuy nhiên, môi trường đa luồng cũng mang lại những phức tạp vốn có, đặc biệt là Race ConditionDeadlock.

Khi làm việc với một Thread duy nhất, tính nhất quán được đảm bảo bởi định nghĩa vì xử lý diễn ra tuần tự, giống như "chỉ có một bàn tay đang thao tác trên dữ liệu". Trong tính toán song song, với các truy cập đồng thời vào bộ nhớ chia sẻ, chúng ta phải đối mặt với hai câu hỏi lớn:

  • Điều gì xảy ra khi các Thread khác nhau tranh giành cùng một tài nguyên tại cùng một thời điểm? (Race Condition)
  • Điều gì xảy ra khi một Thread cần một tài nguyên đang bị Thread khác khóa lại?

Việc duy trì tính nhất quán trong kịch bản này đại diện cho một trong những thách thức lớn nhất của máy tính hiện đại. Giáo sư Edward A. Lee (UC Berkeley) đã lập luận trong bài báo "The Problems with Threads" (2006) rằng:

"[Parallelism] discards the most essential and appealing properties of sequential computation: understandability, predictability, and determinism."

(Tính toán song song loại bỏ những thuộc tính quan trọng và hấp dẫn nhất của tính toán tuần tự: tính dễ hiểu, tính dự đoán và tính xác định.)

Deadlock DiagramDeadlock Diagram

Hiểu về Deadlock

Một giải pháp không phù hợp cho câu hỏi thứ hai có thể dẫn đến vấn đề Deadlock, nơi hai hoặc nhiều Thread chờ đợi vô hạn các tài nguyên mà luồng kia đang nắm giữ.

Deadlock chỉ xảy ra khi chiến lược đồng thời được triển khai hội tụ đủ 4 điều kiện sau:

  • Exclusion (Loại trừ lẫn nhau): Một tài nguyên chỉ được truy cập bởi một luồng tại một thời điểm (thông qua locks, mutexes hoặc semaphores).
  • Hold-and-wait: Luồng giữ tài nguyên đã cấp phát trong khi chờ đợi tài nguyên khác.
  • No preemption (Không thể chiếm đoạt): Tài nguyên đã bị giữ cho một luồng không thể bị "cướp" bởi luồng khác.
  • Circular wait (Chờ đợi vòng tròn): Một chuỗi các luồng đang chờ đợi lẫn nhau, tạo thành một vòng lặp khép kín.

Tuy nhiên, trong ví dụ về tiệm bánh ở trên, nguy cơ xảy ra Deadlock là gần như bằng không. Đây là bài toán kiểu SIMD (Single Instruction, Multiple Data), nơi cùng một thao tác được áp dụng trên một tập dữ liệu với Data Partitioning (mỗi Thread chăm sóc một phạm vi dữ liệu cụ thể). Khi không có chia sẻ trạng thái và việc truy cập dữ liệu diễn ra đồng nhất và độc lập bởi mỗi Thread, việc sử dụng locks thường là không cần thiết.

Kết luận

Tính toán song song là một lĩnh vực rộng lớn đã được nghiên cứu trong nhiều thập kỷ. Các chủ đề trải dài từ bản chất của bài toán đang được giải quyết (đơn lệnh cho đa dữ liệu, đa lệnh cho đơn dữ liệu, v.v.) đến việc lựa chọn mô hình phân phối và xử lý tác vụ (task graph, master-slave, v.v.), bên cạnh các vấn đề như Context Switching và các giới hạn vật lý của tính toán song song.

Tóm lại, bài viết này đã cho thấy cách phần cứng hiện đại được sử dụng để thực hiện các tác vụ đồng thời và sự phức tạp mà nó mang lại. Vậy còn với một ứng dụng cơ sở dữ liệu thì sao? Các khái niệm về song song và đồng thời được triển khai như thế nào? Đó sẽ là nội dung cho một bài viết trong tương lai.

Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗