[STM32 – RTOS] Các trạng thái của Task và Task API

STM32 RTOS Cac trang thai cua Task va Task API

Ở bài trước chúng ta đã tìm hiểu cách tạo Task và lập lịch cho Task, ở bài này chúng ta sẽ tìm hiểu các Task API và các trạng thái của Task. Nắm vững được điều này giúp chúng ta là việc với Task hiệu quả hơn.
Bài 2 về RTOS trong Serie Học lập trình STM32 từ A tới Z

Tìm hiểu về các trạng thái của Task (Task Status)

word image 11065 1

Ready (Sẵn sàng)

Trạng thái Ready là khi một task đã sẵn sàng để được CPU xử lý, nhưng hiện tại chưa được thực thi. Task ở trạng thái này có thể chuyển sang trạng thái Running khi được bộ lập lịch của FreeRTOS chọn.

Running (Đang chạy)

Trạng thái Running là khi task đang được CPU xử lý. Chỉ có một task duy nhất có thể ở trạng thái này tại một thời điểm. Khi task hoàn thành hoặc bị ngắt quãng, nó sẽ chuyển sang trạng thái khác như Blocked hoặc Ready.

Blocked (Bị chặn)

Task chuyển sang trạng thái Blocked khi nó đang chờ một sự kiện hoặc tài nguyên, chẳng hạn như chờ tín hiệu từ một task khác hoặc chờ một khoảng thời gian cụ thể. Khi điều kiện chờ được đáp ứng, task sẽ chuyển về trạng thái Ready.

Suspended (Bị tạm dừng)

Trạng thái Suspended là khi task bị tạm dừng và không được lập lịch để thực thi, cho đến khi nó được tiếp tục (resumed). Đây là trạng thái hữu ích khi cần tạm dừng các task không cần thiết để tiết kiệm tài nguyên.

Deleted (Đã xóa)

Trạng thái Deleted là khi task đã bị xóa và không còn tồn tại trong hệ thống. Khi một task hoàn thành nhiệm vụ của mình hoặc không còn cần thiết, nó có thể được xóa để giải phóng tài nguyên.

Task Switching hay Contex Switching – chuyển đổi Task

Chap 3: Operations of a Real-Time OS | TRON Forum

Context switching là quá trình lưu trữ trạng thái của một task hiện tại và khôi phục trạng thái của task tiếp theo được chọn để thực thi. Trạng thái này bao gồm các thanh ghi CPU, con trỏ ngăn xếp, và các thông tin cần thiết khác để đảm bảo task có thể tiếp tục thực thi từ điểm mà nó bị dừng lại.

  • Lưu trữ ngữ cảnh: Khi một task bị dừng lại, trạng thái hiện tại của CPU và ngăn xếp của task đó được lưu trữ vào một vùng bộ nhớ cụ thể.
  • Khôi phục ngữ cảnh: Trạng thái của task tiếp theo được chọn sẽ được khôi phục từ vùng bộ nhớ này, và CPU sẽ tiếp tục thực thi task từ điểm mà nó bị dừng lại.

Kernel sẽ đảm nhiệm nhiệm vụ switch task, nó sẽ lưu lại context(trạng thái) hiện tại của task bị suspend và khôi phục lại context của task đang được tiếp tục. Kernel sẽ thực hiện công việc này trong các trường hợp

  • Sau khi có định nghĩa trước về thời gian thực thi (execution time), thời gian  time slide được lấy bởi systick interrupt. Hay
  • Khi có event unblock quyền ưu tiên cao hơn (higher priority) xảy ra như signal,queue, semaphore,..
  • Khi task gọi hàm osThreadYield () để thông báo kernel chuyển sang task khác mà không đợi tới kết thúc của time slice

Các Task API thường dùng

Ta có bảng các hàm  API cơ bản của task trong CMSIS RTOSFreeRTOS

Feature CMSIS RTOS API FreeRTOS API
Define task attribute osThreadDef osThreadDef_t
Create task osThreadCreate xTaskCreate
Terminate task osThreadTerminate vTaskDelete
Yield task osThreadYield taskYield
Delay task osDelay vTaskDelay
Get task ID osThreadGetID xTaskGetCurrentTaskHandle
Set task priority osThreadSetPriority vTaskPrioritySet
Get task priority osThreadGetPriority uxTaskPriorityGet
Suspend task osThreadSuspend vTaskSuspend
Suspend all task osThreadSuspendAll vTaskSuspendAll
Resume task osThreadResume vTaskResume
Resume all task osThreadResumeAll vTaskResumeAll
Get state of task osThreadState eTaskGetState
List current tasks info osThreadList vTaskList
Delay task until specified time osDelayUntil vTaskDelayUntil

Ghi chú:

  • CMSIS RTOS API: Là một giao diện chuẩn hóa cho các hệ điều hành thời gian thực (RTOS) trong các vi điều khiển ARM Cortex-M, giúp tạo ra mã nguồn độc lập với RTOS.
  • FreeRTOS API: Là giao diện API của FreeRTOS, một RTOS phổ biến cho các hệ thống nhúng.

Một số API thường dùng như:

  1. osThreadCreate: Tạo và khởi động một thread (task) mới.
  2. osThreadTerminate: Kết thúc một thread (task).
  3. osThreadSuspend: Treo một thread (task) không cho thực thi.
  4. osThreadResume: Tiếp tục thực thi một thread (task) đã bị treo.
  5. osDelay: Đưa thread vào trạng thái chờ trong một khoảng thời gian xác định.
  6. osThreadGetId: Lấy ID của thread hiện tại.
  7. osThreadSetPriority: Đặt lại độ ưu tiên của một thread.
  8. osThreadGetPriority: Lấy độ ưu tiên hiện tại của một thread.
  9. osThreadYield: Chuyển quyền kiểm soát CPU cho thread khác có cùng độ ưu tiên.
  10. osKernelStart: Bắt đầu bộ lập lịch của RTOS.

Trạng thái Ready, Running và Blocked

Khi Nào Task Ở Trạng Thái Ready

Khi Task Được Tạo: Khi một task mới được tạo bằng cách gọi osThreadNew trong CMSIS RTOS hoặc xTaskCreate trong FreeRTOS, task sẽ ở trạng thái “Ready” và chờ để được bộ lập lịch chọn để chạy.

Khi Task Chuyển Từ Blocked Sang Ready: Sau khi một task bị blocked bởi osDelay, osSemaphoreAcquire, osMutexAcquire, osMessageQueueGet, hoặc osEventFlagsWait, và điều kiện chờ đã được thỏa mãn (thời gian delay kết thúc, semaphore hoặc mutex có sẵn, có dữ liệu trong queue, hoặc sự kiện xảy ra), task sẽ chuyển từ trạng thái “Blocked” sang “Ready”.

Khi Task Chuyển Từ Suspended Sang Ready: Khi một task bị treo (suspended) bởi osThreadSuspend trong CMSIS RTOS hoặc vTaskSuspend trong FreeRTOS, và sau đó được tiếp tục (resumed) bởi osThreadResume hoặc vTaskResume, task sẽ chuyển từ trạng thái “Suspended” sang “Ready”.

Khi Task Được Giải Phóng từ Waiting List: Khi một task đang chờ trong danh sách chờ của một hàng đợi (queue) hoặc semaphore và điều kiện chờ đã được thỏa mãn, nó sẽ chuyển sang trạng thái “Ready”.

Khi nào Task ở trạng thái Blocked

Chờ Delay: Khi một task gọi hàm osDelay trong CMSIS RTOS hoặc vTaskDelay trong FreeRTOS, task sẽ ở trạng thái blocked cho đến khi thời gian delay kết thúc.

Chờ Semaphore: Khi một task đang chờ semaphore bằng cách gọi osSemaphoreAcquire trong CMSIS RTOS hoặc xSemaphoreTake trong FreeRTOS, nếu semaphore không có sẵn, task sẽ bị blocked cho đến khi semaphore được giải phóng.

Chờ Mutex: Khi một task đang chờ mutex bằng cách gọi osMutexAcquire trong CMSIS RTOS hoặc xSemaphoreTake (với mutex) trong FreeRTOS, nếu mutex không có sẵn, task sẽ bị blocked cho đến khi mutex được giải phóng.

Chờ Message/Queue: Khi một task đang chờ để nhận dữ liệu từ queue bằng cách gọi osMessageQueueGet trong CMSIS RTOS hoặc xQueueReceive trong FreeRTOS, nếu queue rỗng, task sẽ bị blocked cho đến khi có dữ liệu.

Chờ Event/Signal: Khi một task đang chờ một sự kiện hoặc tín hiệu bằng cách gọi osEventFlagsWait trong CMSIS RTOS, nếu sự kiện hoặc tín hiệu chưa được thiết lập, task sẽ bị blocked cho đến khi sự kiện hoặc tín hiệu đó xảy ra.

Lập trình STM32 RTOS trạng thái Blocked

Trong bài trước: STM32 Schedule chúng ta đã biết cách tạo Task và Run Task. Chúng ta sẽ xét chi tiết các trạng thái của Task trong ví dụ đó.

A black screen with white dots Description automatically generated

Với Task 3 có độ ưu tiên là High, default Task là Normal và Task 2 có độ ưu tiên Low.

Khi khởi tạo Task bằng lệnh: defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

Task ở trạng thái Ready: Sẵn sàng để Running

Khi osKernelStart(); được gọi, dựa vào độ ưu tiên của các Task, Kernel sẽ chạy Task 3 đầu tiên.

Lúc này Task 3 sẽ ở States Running: chúng ta in chuỗi ra qua cổng UART1 do đó ta thấy chuỗi Task 3… sẽ được in ra.

Sau đó gọi hàm osDelay(1000);

Khi gọi Delay, Task 3 sẽ chuyển về Trạng thái Blocked. Trong trường hợp này Task 3 sẽ ở trạng thái Blocked trong vào 1000ms

A screenshot of a computer code Description automatically generated

Trong thời gian này, Kernel chuyển sang Task có độ ưu tiên Thấp hơn là Default Task, tiếp tục như vậy tới Task 2.

Khi hết thời gian osDelay, Task sẽ chuyển lại về trạng thái Ready, sau đó được Kernel tiếp tục khởi chạy theo độ ưu tiên.

Khi xem Log UART các bạn sẽ thấy. Cả 3 task được in gần như ngay lập tức (cách nhau khoảng 1ms = Thời gian Time Slice) , sau đó delay khoảng 1s rồi lại in cả 3.

Do cả 3 task đều có thời gian bị Blocked là 1000ms

Trạng thái Suspended

Khi Nào Task Ở Trạng Thái Suspended

Khi Task Bị Treo Một Cách Chủ Động: Một task chuyển sang trạng thái “Suspended” khi gọi các hàm osThreadSuspend trong CMSIS RTOS hoặc vTaskSuspend trong FreeRTOS.

Treo Chính Nó: Một task có thể tự treo chính nó bằng cách gọi osThreadSuspend hoặc vTaskSuspend với handle của chính nó.

Lập trình STM32 RTOS sử dụng task Suspend một task khác

Thực hiện tạo 2 Task: Defautl Task với độ ưu tiên Normal, Task 2 có độ ưu tiên Low

Gen code và lập trình trên 2 Task như sau:

A screenshot of a computer program Description automatically generated

Task Default có độ ưu tiên cao hơn sẽ chạy trước, sau đó Suspend sau 1s và Resume Task 2 sau 3s

Trong khi Task Default bị delay lần đầu tiên (delay 1s)

Task 2 sẽ được khởi chạy và in log mỗi 200ms

Kết quả

Giải thích kết quả

  • 0ms: defaultTask bắt đầu, log “defaultTask (normal) is Running\r\n”
  • 1ms: task2 log “task2 (low) is Running\r\n”
  • 201ms: task2 log “task2 (low) is Running\r\n”
  • 401ms: task2 log “task2 (low) is Running\r\n”
  • 601ms: task2 log “task2 (low) is Running\r\n”
  • 801ms: task2 log “task2 (low) is Running\r\n”
  • 1000ms: defaultTask log “Suspending task2 (low)\r\n”, task2 bị treo
  • 3000ms: defaultTask log “Resuming task2 (low)\r\n”, task2 được tiếp tục
  • 3200ms: task2 log “task2 (low) is Running\r\n”
  • Tiếp tục vòng lặp như vậy

Lập trình STM32 RTOS task tự suspend chính nó

Chúng ta sẽ dùng Task defaul để resume cho task 2.

Task 2 sẽ tự Suspend chính nó mỗi 1s

A screenshot of a computer program Description automatically generated

Log in ra sẽ như sau:

0ms: defaultTask bắt đầu, log “defaultTask (normal) is Running\r\n” và vào trạng thái Blocked trong 2s

1ms: task2 log “task2 (low) is Running\r\n” sau đó vào trạng thái Blocked trong 1

1000ms: task2 log “task2 (low) is Suspending itself\r\n”, task2 tự treo chính nó

2000ms: defaultTask log “Resuming task2 (low)\r\n”, task2 chuyển trạng thái sang Ready

2001ms: Kernal chuyển task sau đó task2 log “task2 (low) is Running\r\n” và tiếp tục bị block trong 1s

3000ms: task2 log “task2 (low) is Suspending itself\r\n”, task2 tự treo

4000ms: defaultTask log “defaultTask (normal) is Running\r\n”

6000ms: defaultTask log “Resuming task2 (low)\r\n”, task2 được tiếp tục

6001ms: task2 log “task2 (low) is Running\r\n”

7000ms: task2 log “task2 (low) is Suspending itself\r\n”, task2 tự treo

Trạng thái Deleted

Khi nào Task ở trạng thái Deleted

Task có thể chuyển sang trạng thái deleted (bị xóa) khi nó tự kết thúc hoặc xóa bởi một task khác. Trạng thái deleted có nghĩa là task đã bị loại khỏi danh sách các task đang chạy và tài nguyên của nó sẽ được giải phóng và sử dụng lại.

Ví dụ:

  • osThreadTerminate(task2Handle); // Xóa task2
  • osThreadExit (); // Xóa chính nó

Lập trình STM32 RTOS bị Task khác delete

A screenshot of a computer program Description automatically generated

Task Default sẽ được khởi chạy và in Log, sau đó vào trạng thái Blocked trong 5s

Trong thời gian đó, Task 2 sẽ được khởi chạy và Log 5s

Khi hết thời gian Blocked của Default Task sẽ xóa Task 2. Sau đó rơi vào vòng for để in log mỗi 1s

Task 2 sau khi bị xóa bộ nhớ sẽ được giải phóng và không còn được lập lịch để chạy nữa.

Kết quả:

  • 0ms: defaultTask bắt đầu, log “defaultTask (normal) is Running\r\n”
  • 1ms: task2 bắt đầu, log “task2 (low) is Running\r\n”
  • 1000ms: task2 log “task2 (low) is Running\r\n”
  • 2000ms: task2 log “task2 (low) is Running\r\n”
  • 3000ms: task2 log “task2 (low) is Running\r\n”
  • 4000ms: task2 log “task2 (low) is Running\r\n”
  • 5000ms: defaultTask log “Deleting task2 (low)\r\n”, task2 bị xóa
  • 5001ms: defaultTask tiếp tục log “defaultTask (normal) is Running\r\n”
  • 6000ms: defaultTask log “defaultTask (normal) is Running\r\n”
  • Sau đó chỉ có Default task chạy

Lập trình STM32 RTOS tự delete chính nó

A screenshot of a computer code Description automatically generated

Khi mới bắt đầu, Default Task sẽ được chạy trước và in Log sau đó vào trạng thái Blocked trong 1s.

Ngay sau đó Task 2 có độ ưu tiên thấp hơn sẽ được chạy và in log, và vào trạng thái Blocked trong 1s

Sau 1s, default Task được gọi và in log và lại vào Blocked

Ngay sau đó Task 2 hết blocked và chạy lệnh osTheadExit (tự xóa chính mình). Sau lệnh này Task 2 đã bị xóa.

Hệ thống chỉ còn lại Task Default chạy và in log mỗi 1s

Kết quả:

  • 0ms: defaultTask bắt đầu, log “defaultTask (normal) is Running\r\n”
  • 1ms: task2 bắt đầu, log “task2 (low) is Running and will delete itself\r\n”
  • 1000ms: defaultTask log “defaultTask (normal) is Running\r\n”
  • 1001ms: task2 log “task2 (low) is now deleting itself\r\n” và sau đó task2 tự xóa
  • 2000ms: defaultTask log “defaultTask (normal) is Running\r\n”
  • 3000ms: defaultTask log “defaultTask (normal) is Running\r\n”

Kết

Nắm vững các trạng thái của Task giúp cho việc điều khiển Task một cách mượt mà hơn. Các task đôi khi phải cần dừng lại (suspend) để chờ tài nguyên hoặc phải bị xóa đi để giải phóng tài nguyên cho các tác vụ khác.

Hi vọng bài viết này có ích với bạn, hẹn gặp lại trong bài tiếp theo.

 

5/5 - (1 bình chọn)

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *