🌱 Core 18. RTOS - Counting Semaphore
Ở post trước chúng ta đã cùng tìm hiểu về Binary Semaphore, là một trong các cơ chế đồng bộ task trong RTOS. Thì binary semaphore dùng để quản lý đồng bộ 1 hoạt động duy nhất (ở post trước là ví dụ về hoạt động in ra của chiếc máy in). Vậy, với việc đồng bộ nhiều hoạt động, chúng ta cần một cơ chế khác tổng quát hơn, đó là Counting Semaphore.
Thực chất Binary Semaphore là một trường hợp đặc biệt của Counting Semaphore, với chiếc chìa khóa - key chỉ có 2 giá trị là 1 hoặc 0 (đúng với tên gọi binary). Trong khi đó, với Counting Semaphore, chiếc chìa khóa - key này có thể mang giá trị trong một rải giá trị (thường là từ 0 đến 255).
👉 Công dụng của Counting Semaphore
Counting Semaphore thường được sử dụng với 2 mục đích:
- Counting Event - Đếm sự kiện
- Semaphore trong trường hợp này giống như một biến đếm, hoạt động theo cơ chế give - take.
- Mỗi lần có sự kiện xảy ra, một trình xử lý sẽ give một semaphore (tương đương với tăng biến đếm lên 1 đơn vị).
- Ngược lại, mỗi lần một sự kiện được xử lý xong sẽ take một semaphore (tương đương với việc giảm biến đếm đi 1 đơn vị).
- Do đó, giá trị biếm đếm = số sự kiện đã xảy ra - số sự kiện đã xử lý. Mặc định khi khởi tạo, giá trị đếm này là 0 (không có sự kiện nào).
- Resource Management - Quản lý tài nguyên
- Cũng có một giá trị đếm để đếm số lượng các tài nguyên có sẵn. Khi giá trj này bằng 0 thì sẽ không có tài nguyên nào free cả. Mặc định khi khởi tạo, giá trị này bằng MAX (có thể là 255).
- Khi một task dùng một tài nguyên, nó sẽ Acquire semaphore để giảm biến đếm đi một đơn vị.
- Ngược lại, sau khi sử dụng xong nó sẽ Release lại để tăng biến đếm lên một đơn vị.
![]() |
Counting Semaphore |
👉 Counting Semaphore Example
Một ví dụ cho thấy hoạt động của Counting Semaphore, có 3 task cùng priority đang hoạt động như trên (lập lịch kiểu round-robin các task sẽ chạy hết time-slice). (Các bạn có thể xem lại bài Scheduler tại đây)
- Theo thứ tự các time-slice các task đang thực hiện thì task A đang thực hiện đầu tiên, task B và task C lần lượt nằm trong queue của scheduler để sẵn sàng thực thi. Task A gọi hàm osSemaphoreWait (kiểm tra xem có tài nguyên nào free không?). Kết quả lúc này biến đếm Semaphore = 2, task A sẽ Acquire Semaphore, dẫn đến counting semaphore giảm xuống còn 1.
- Hết time-slice của mình thì task A trở lại trạng thái ready để nhường quyền task B. Tương tự như task A thì task B cũng gọi osSemaphoreWait và Acquire Semaphore dẫn đến việc counting semaphore giảm xuống còn 0 (Tức là không còn resoure nào free cả !!!). Hết time-slice task B nhường quyền cho task C.
- Task C vẫn chạy bình thường cho đến vị trí ➀ thì task C gọi hàm osSemaphoreWait để yêu cầu tài nguyên!
- Nhưng tiếc là không còn tài nguyên nào cả ! (Counting Semaphore = 0). Điều này dẫn đến việc task C phải chờ tài nguyên, nó rơi vào trạng thái waiting, vị trí ➁. Vì vậy task đang Ready là task A sẽ được Scheduler cấp quyền chạy tiếp.
⇨ Lúc này chỉ còn là cuộc chơi của task A và task B nếu không ai chịu nhả tài nguyên ra. - Task A chạy hết time-slice rồi đến task B, lúc này tại điểm số ➂ task B gọi hàm osSemaphoreRelease để nhả tài nguyên. Lúc này task C mới nhận thấy có tài nguyên để sử dụng rồi nên nó thoát khỏi trạng thái waiting, do cùng priority nên task C được xếp cuối hàng chờ ready. Và đợi task B thực thi xong time-slice, rồi đến task A hết time-slice, rồi lúc này tại điểm số ➃ thì task C mới có thể trở lại thực thi.
Trên đây là hoạt động của Counting Semaphore, có rất nhiều trường hợp khác có thể xảy ra trên thực tế. Các bạn nên thực hành nó trong một bài toán thực tế để hiểu hơn về Semaphore cũng như RTOS.
0 Nhận xét