Chủ đề xuất hiện trong hai quan điểm: hệ điều hành và ngôn ngữ lập trình. Trong cả hai trường hợp, có một số biến thể trong những thuộc tính mà một luồng có.
Một định nghĩa tối thiểu của một chủ đề là nó là thứ xảy ra theo trình tự, hết thứ này đến thứ khác.
Trong một mô hình thực thi máy điển hình, mỗi luồng có một bộ các thanh ghi mục đích chung và bộ đếm chương trình riêng. Nếu máy đặt ra một thanh ghi cụ thể dưới dạng con trỏ ngăn xếp, thì sẽ có một bản sao cho mỗi luồng.
Từ góc độ hệ điều hành, tối thiểu một hệ điều hành cần làm để hỗ trợ các luồng là cung cấp một cách để chuyển đổi giữa chúng. Điều này có thể xảy ra tự động ( đa nhiệm ưu tiên hoặc chỉ khi luồng đưa ra yêu cầu rõ ràng (đa nhiệm hợp tác; trong trường hợp đó, các luồng đôi khi được gọi là các sợi ). Ngoài ra còn có các mô hình lai với cả năng suất ưu tiên và hợp tác, ví dụ như giữa các luồng của các nhóm khác nhau hoặc các tác vụ nhưng mang lại năng suất rõ ràng giữa các luồng của cùng một nhóm / tác vụ. Chuyển đổi giữa các luồng liên quan đến việc lưu tối thiểu các giá trị thanh ghi của luồng cũ và khôi phục các giá trị thanh ghi của luồng mới.
Trong một hệ điều hành đa nhiệm cung cấp sự tách biệt giữa các tác vụ (hoặc các quy trình , bạn có thể coi các thuật ngữ này là từ đồng nghĩa trong ngữ cảnh HĐH), mỗi tác vụ có tài nguyên riêng, trong không gian địa chỉ cụ thể, nhưng cũng có tệp mở, đặc quyền, v.v. được cung cấp bởi nhân hệ điều hành , một thực thể nằm trên các quy trình. Mỗi tác vụ thường có ít nhất một luồng - một tác vụ không thực thi mã sẽ không được sử dụng nhiều. Hệ điều hành có thể hoặc không thể hỗ trợ nhiều luồng trong cùng một tác vụ; ví dụ như Unix ban đầu thì không. Một tác vụ vẫn có thể chạy nhiều luồng bằng cách sắp xếp để chuyển đổi giữa chúng - điều này không yêu cầu bất kỳ đặc quyền đặc biệt nào. Đây được gọi là chủ đề người dùngĐặc biệt, trong một bối cảnh Unix. Ngày nay, hầu hết các hệ thống Unix đều cung cấp các luồng nhân, đặc biệt bởi vì đó là cách duy nhất để có nhiều luồng của cùng một tiến trình chạy trên các bộ xử lý khác nhau.
Hầu hết các tài nguyên hệ điều hành ngoài thời gian tính toán được gắn vào các tác vụ, không phải các luồng. Một số hệ điều hành (ví dụ: Linux) phân định rõ ràng các ngăn xếp, trong trường hợp đó, mỗi luồng có một luồng riêng; nhưng có những hệ điều hành mà hạt nhân không biết gì về ngăn xếp, chúng chỉ là một phần của đống dữ liệu có liên quan. Kernel cũng thường quản lý bối cảnh kernel cho mỗi luồng, đó là cấu trúc dữ liệu chứa thông tin về những gì luồng đang làm; điều này cho phép kernel xử lý nhiều luồng bị chặn trong một cuộc gọi hệ thống cùng một lúc.
Theo như hệ điều hành, các luồng của một tác vụ chạy cùng một mã, nhưng ở các vị trí khác nhau trong mã đó (các giá trị bộ đếm chương trình khác nhau). Có thể hoặc không thể xảy ra rằng một số phần nhất định của mã chương trình luôn được thực thi trong một luồng cụ thể, nhưng thường có mã chung (ví dụ: các hàm tiện ích) có thể được gọi từ bất kỳ luồng nào. Tất cả các luồng nhìn thấy cùng một dữ liệu, nếu không, chúng sẽ được coi là các nhiệm vụ khác nhau; nếu một số dữ liệu chỉ có thể được truy cập bởi một luồng cụ thể, thì đó thường chỉ là mục đích của ngôn ngữ lập trình, không phải của hệ điều hành.
Trong hầu hết các ngôn ngữ lập trình, lưu trữ được chia sẻ giữa các luồng của cùng một chương trình. Đây là một mô hình bộ nhớ chia sẻ của lập trình đồng thời; nó rất phổ biến, nhưng cũng rất dễ bị lỗi, bởi vì lập trình viên cần cẩn thận khi cùng một dữ liệu có thể được truy cập bởi nhiều luồng vì điều kiện cuộc đua có thể xảy ra. Lưu ý rằng ngay cả các biến cục bộ cũng có thể được chia sẻ giữa các luồng: Biến cục bộ của người dùng (thường) có nghĩa là một biến có tên chỉ hợp lệ trong một lần thực hiện hàm, nhưng một luồng khác có thể lấy một con trỏ tới biến đó và truy cập vào nó.
Ngoài ra còn có các ngôn ngữ lập trình trong đó mỗi luồng có lưu trữ riêng và giao tiếp giữa chúng diễn ra bằng cách gửi tin nhắn qua các kênh liên lạc. Đây là mô hình truyền thông điệp của lập trình đồng thời. Erlanglà ngôn ngữ lập trình chính tập trung vào việc truyền thông điệp; môi trường thực thi của nó có xử lý các luồng rất nhẹ và nó khuyến khích các chương trình được viết bằng nhiều luồng ngắn, ngược lại với hầu hết các ngôn ngữ lập trình khác, nơi tạo ra một luồng là một hoạt động tương đối tốn kém và môi trường thời gian chạy không thể hỗ trợ rất lớn số lượng chủ đề cùng một lúc. Tập hợp con tuần tự của Erlang (một phần của ngôn ngữ xảy ra trong một luồng, đặc biệt là thao tác dữ liệu) (phần lớn) hoàn toàn là chức năng; do đó, một luồng có thể gửi tin nhắn đến một luồng khác chứa một số dữ liệu và không luồng nào cần phải lo lắng về việc dữ liệu bị luồng khác sửa đổi trong khi nó đang sử dụng nó.
Một số ngôn ngữ pha trộn hai mô hình bằng cách cung cấp lưu trữ cục bộ luồng, có hoặc không có hệ thống loại để phân biệt vị trí lưu trữ luồng cục bộ với vị trí toàn cầu. Lưu trữ cục bộ thường là một tính năng tiện lợi cho phép một tên biến để chỉ định các vị trí lưu trữ khác nhau trong các luồng khác nhau.
Một số theo dõi (khó) có thể được quan tâm để hiểu chủ đề là gì:
- Mức tối thiểu mà kernel cần làm để hỗ trợ nhiều luồng là gì?
- Trong môi trường đa bộ xử lý, cần gì để di chuyển một luồng từ bộ xử lý này sang bộ xử lý khác?
- Điều gì sẽ xảy ra để triển khai đa luồng ( coroutines ) hợp tác trong ngôn ngữ lập trình yêu thích của bạn mà không có sự hỗ trợ từ hệ điều hành và không sử dụng hỗ trợ tích hợp nếu có? (Xin lưu ý rằng hầu hết các ngôn ngữ lập trình đều thiếu các nguyên hàm cần thiết để triển khai coroutines bên trong một luồng.)
- Một ngôn ngữ lập trình có thể trông như thế nào nếu nó có sự tương tranh nhưng không có khái niệm (rõ ràng) về các luồng? (Ví dụ chính: phép tính pi .)