FreeRTOS Mutex, Recursive Mutex

FreeRTOS Mutex

Mutex là binary semaphore mà có cơ chế kế thừa ưu tiên (priority inheritance mechanism). Trong khi binary semaphore là lựa chọn tốt hơn để thực hiện đồng bộ hóa (giữa các task hoặc giữa các task và một interrupt), thì mutex là lựa chọn tốt hơn để thực hiện loại trừ lẫn nhau đơn giản (simple mutual exclusion), do đó MUTual EXclusion.

Khi được dùng để loại trừ lẫn nhau, mutex hoạt động giống như một token được dùng để bảo vệ một tài nguyên (resource). Khi một task muốn truy cập vào tài nguyên, trước tiên nó phải chiếm lấy (‘take’) token. Khi sử dụng xong tài nguyên, nó phải ‘give’ lại token – để cho phép các task khác có cơ hội được truy cập vào cùng tài nguyên đó.

Mutex sử dụng các hàm API truy cập giống của semaphore nên cũng cho phép chỉ định thời gian chặn (block time). Block time chỉ thị số lượng ‘tick’ tối đa mà một task sẽ chuyển sang trạng thái Blocked khi cố gắng ‘take’ một mutex nếu mutex đó không có sẵn ngay lúc đó. Tuy nhiên, không giống như binary semaphore – mutex sử dụng tính kế thừa ưu tiên (priority inheritance). Điều này có nghĩa là nếu một task có độ ưu tiên cao bị block trong khi cố gắng lấy một mutex (token) mà hiện tại đang được giữ bởi một task có độ ưu tiên thấp hơn, thì độ ưu tiên của task giữ token sẽ tạm thời được nâng lên thành task đang bị block. Cơ chế này được thiết kế để đảm bảo task có mức độ ưu tiên cao hơn bị giữ ở trạng thái bị block trong thời gian ngắn nhất có thể, và nhờ đó giảm thiểu đảo ngược độ ưu tiên (priority inversion) đã xảy ra.

Kế thừa ưu tiên (priority inheritance) không trị được tình trạng đảo ngược ưu tiên (priority inversion)! Nó chỉ giảm thiểu ảnh hưởng của nó trong một số trường hợp. Các ứng dụng thời gian thực cứng (hard real time application) phải được thiết kế sao cho priority inversion không xảy ra ngay từ lúc đầu.

Không nên sử dụng mutex trong một interrupt bởi vì:

  • Mutex bao gồm một cơ chế kế thừa ưu tiên chỉ có ý nghĩa nếu mutex được give và take từ một task chứ không phải một interrupt.
  • Một interrupt không thể block để chờ tài nguyên được bảo vệ bởi mutex đến khi khả dụng (available)

FreeRTOS Recursive Mutex

Một mutex sử dụng đệ quy (recursive) có thể được ‘take’ nhiều lần bởi owner. Mutex không trở nên khả dụng (available) cho đến khi owner gọi xSemaphoreGiveRecursive() cho mỗi yêu cầu xSemaphoreTakeRecursive() thành công. Ví dụ: nếu một task ‘take’ thành công cùng một mutex 5 lần thì mutex đó sẽ không available cho bất kỳ task nào khác cho đến sau khi task đó ‘give’ trả lại mutex đó đúng 5 lần.

Loại semaphore này sử dụng một cơ chế kế thừa ưu tiên (priority inheritance mechanism) mà một task đang ‘take’ một semaphore PHẢI LUÔN LUÔN ‘give’ trả lại semaphore đó một khi semaphore không cần thiết nữa.

Các loại mutex không thể được sử dụng bên trong các trình phục vụ ngắt (interrupt service routine).

Icons made by Freepik from www.flaticon.com