Các khái niệm cần chú ý khi làm việc với RTOS

Chú ý khi làm việc với RTOS

Mutex

Mutex là gì

Trên một hệ điều hành thường có nhiều chương trình (hay tác vụ - task) chạy đồng thời. Mutex giúp ngăn chặn việc hai task cùng truy cập vào 1 tài nguyên (memory, register gọi chung là critical section) của hệ thống trong cùng một thời điểm.

Ví dụ, ta có 1 cái FIFO, task 1 đang read FIFO, task 2 lại write FIFO, nếu task 1 chưa lấy xong phần dữ liệu cần thiết mà task 2 lại write đè vào đúng vị trí task 1 đang read, nó sẽ làm sai lệch dữ liệu mà task 1 đang đọc.

Lưu ý: Cơ chế mutex được dùng trong cả thiết kế hardware và software.

Dùng trong chương trình như thế nào

Hiểu đơn giản, mutex giống như cái khóa tủ dùng chung khi vào hiệu sách hay siêu thị. Để mở được tủ thì phải có khóa. Dùng xong tủ thì phải trả lại chìa khóa lại cho thằng khác dùng.

Ví dụ:

void task1()
{
    //Đợi lấy chìa khóa để mở tủ
    osMutexWait();
    //Cất mủ, cặp, túi sách...
    @to do
    //Trả chìa khóa khi xong việc
    osMutexRelease();
}

Semaphore

Semaphore là gì

Semaphore là 1 cái advance mutex. Dùng để quản lý và bảo vệ tài nguyên dùng chung(share resource). Mutex được gọi là 1 cái binary semaphore.

Nguyên tắc hoạt động của semaphore như hình dưới:

Semaphore

Nó giống như 1 cái hàng đợi (queue). Các thread/task khác nhau khi có yêu cầu sử dụng tài nguyên dùng chung sẽ bị tống vào hàng đợi này. Khi nhận được semaphore token thì thread nào được tống vào queue trước thì sử dụng tài nguyên trước. Sau đó nó lại release ra cho thread khác dùng.

Dùng như thế nào

Cách dùng tương tự giống mutex.

Sự khác nhau giữa SEMAPHORES và MUTEXES

Mailbox (or Message queue)

Mailbox là gì

Mailbox là 1 cái “hôp thư” :D. Một mailbox chứa nhiều lá thư (messages). Thực ra nó là một cái FIFO viết cho RTOS.

Mailbox

Ví dụ sử dụng mailbox trong RTX:

Định nghĩa một mailbox gồm 20 messages

os_mbx_declare (mailbox1, 20);

Khởi tạo mailbox

os_mbx_init (&mailbox1, sizeof(mailbox1));

Kiểm tra mailbox còn chỗ trống để cho tiếp message mới vào không?

if (os_mbx_check (&mailbox1) == 0) {
    printf("Mailbox is full.\n");
}

Cho thêm message mới vào mailbox

os_mbx_send (&mailbox1, msg, 0xFFFF);

Lấy message ra để xử lý. Sau đó size của mailbox sẽ giảm đi 1.

    void *msg;
    ..
    if (os_mbx_wait (&mailbox1, &msg, 10) == OS_R_TMO) {
        printf ("Wait message timeout!\n");
    }
    else {
        /* process message here */
    free (msg);
    }

Deadlock

Đây là khái niệm mô tả 1 trong những trạng thái treo của hệ thống. Nó xảy ra khi hai (hoặc nhiều) luồng đứng đợi luồng kia chạy xong rồi mới hoạt động tiếp. Giống như là 2 thằng nhân viên cùng làm việc trong 1 phòng và cùng nói một câu:

“Mày làm xong việc của mày thì tao mới làm tiếp được”

Kết quả là: công việc mãi không được hoàn thành đến khi thằng sếp về và cho cả 2 thằng out of jobs (reset hệ thống :D).

Round-Robin (Hay Round - Robin Scheduling)

Là một thuật toán giúp quản lý các task (process hoặc job…vvv) chạy “đồng thời” hay là chạy song song thì đúng hơn. Chương trình sẽ phân chia ra các “time slice”(hoặc time slot) giống như chia 1 cái bánh hình tròn. Về cơ bản, cái bánh cứ quay tròn, đến lượt thằng task nào thì thằng ấy gặm (sử dụng CPU và cái tài nguyên khác) hết phần của mình thì thôi.

Thường thì, các miếng bánh được cắt bằng nhau cho tất cả các task, và các task cũng được thực hiện một cách tuần tự. Vấn đề nảy sinh là?

Thời gian thực hiện task lớn hơn time-slice

Task đó chạy hết time-slice, nó sẽ hold-on (suspended, hay bị CPU seize). Đến vòng lặp sau, thì nó lại tiếp tục chạy tiếp…cứ như thế đến khi xong task thì thôi.

Ví dụ:

Thời gian thực hiện task nhỏ time-slice

Điều này đơn giản, ta làm xong việc sớm thì ta được ngồi chơi..

Trong thực tế có vài biến thể của RRS,

Để giải quyết vấn đề “ngồi chơi” khi task xong sớm

Người ta tạo ra các RRS có time-slot không đều nhau. RRS sẽ call thằng task nào ready (hoặc có priority cao hơn) thực hiện ngay sau khi một task done.

Ví dụ về RRS:

RRS

Với trường hợp sử dụng RTOS, sẽ có một hằng số trong file nào đó mô tả giá trị của time_slot.

Với RTX thì thông số về Round-Robin sẽ đặt trong file RTX_config.c

#define OS_ROBIN 1 // allow use Round Robin or not
#define OS_ROBINTOUT 5 //It is specified in number of system timer ticks, this is time-slice value