Mutex
是一種可以將執行緒進行同步處理的方式,使用 lock 和 unlock 的方式來共享資源使用。
Mutex
的方法無法被 ISR (interrupt service routines)所使用。
以下為 Mutex
的示意圖 :
以下為 Mutex
的範例程式 :
#include "mbed.h"
#include "rtos.h"
Mutex stdio_mutex;
void notify(const char* name, int state) {
stdio_mutex.lock();
printf("%s: %d\n\r", name, state);
stdio_mutex.unlock();
}
void test_thread(void const *args) {
while (true) {
notify((const char*)args, 0); Thread::wait(1000);
notify((const char*)args, 1); Thread::wait(1000);
}
}
int main() {
Thread t2;
Thread t3;
t2.start(callback(test_thread, (void *)"Th 2"));
t3.start(callback(test_thread, (void *)"Th 3"));
test_thread((void *)"Th 1");
}
利用 lock() 來使 stdio 正常運作,並用 unlock()釋放資源。
在 ARM C 標準函式庫內已經存在 Mutex 。主要是可以讓 stdio 進行正常運作,因此以上的範例在實作時並不是必須,除非有些沒有以上保護機制的開發板才需要以上程式碼,如 ARM M0 系列。
正是因為 ARM C 標準函式庫在使用 stdio 時會使用到 Mutex,所以在 ISR 中變無法使用 printf, putc, getc, malloc 和 new 。
Thread class 中的 wait() function 中間是以毫秒為單位,使用 Thread::wait(1000) 是該 funciotn 下 全部 thread 暫停一秒, t1.wait(500) 是 t1 該物件暫停 0.5 秒。
相關語法請參考 : Mutex。
Semaphore
可以用來管理多種特定線程使用共享資源 (a pool of shared resources) 的情況。
以下為 Semaphore
的示意圖 :
以下為 Semaphore
的範例程式 :
#include "mbed.h"
#include "rtos.h"
Semaphore two_slots(2); //宣告兩執行緒的Semaphore
void test_thread(void const *name) {
while (true) {
two_slots.wait();
printf("%s\n\r", (const char*)name);
Thread::wait(1000);
two_slots.release();
}
}
int main (void) {
Thread t2;
Thread t3;
t2.start(callback(test_thread, (void *)"Th 2"));
t3.start(callback(test_thread, (void *)"Th 3"));
test_thread((void *)"Th 1");
}
可管理同時要釋放多少資源來處理執行緒。
相關語法請參考 : Semaphore。
在資料結構中我們學過 Queue
,即是 FIFO (Frist In Frist Out) 的結構,在實作執行緒排程時就會使用到此種結構方式。
以下為 Queue
的示意圖 :
常用指令 :
Queue () //Create and initialise a message Queue .
Queue< T, queue_sz >
osStatus put (T *data, uint32_t millisec=0) //Put a message in a Queue ; T : templete
osEvent get (uint32_t millisec=osWaitForever)//Get a message or Wait for a message from a Queue .
相關語法請參考 : Queue。
MemoryPool
是用來定意並管理記憶體空間的程式。混合 Queue
的函式我們可以得到以下範例程式 :
#include "mbed.h"
#include "rtos.h"
typedef struct {
float voltage; /* AD result of measured voltage */
float current; /* AD result of measured current */
uint32_t counter; /* A counter value */
} message_t;
MemoryPool<message_t, 16> mpool;
Queue<message_t, 16> queue;
/* Send Thread */
void send_thread (void) {
uint32_t i = 0;
while (true) {
i++; // fake data update
message_t *message = mpool.alloc();
message->voltage = (i * 0.1) * 33;
message->current = (i * 0.1) * 11;
message->counter = i;
queue.put(message);
Thread::wait(1000);
}
}
int main (void) {
Thread thread;
thread.start(callback(send_thread));
while (true) {
osEvent evt = queue.get();
if (evt.status == osEventMessage) {
message_t *message = (message_t*)evt.value.p;
printf("\nVoltage: %.2f V\n\r" , message->voltage);
printf("Current: %.2f A\n\r" , message->current);
printf("Number of cycles: %u\n\r", message->counter);
mpool.free(message);
}
}
}
常用指令 :
MemoryPool< T, pool_sz > //Create and Initialize a memory pool.
MemoryPool ()
T* alloc (void) //Allocate a memory block of type T from a memory pool.
T* calloc (void) //Allocate a memory block of type T from a memory pool and set memory block to zero.
osStatus free (T *block) //Return an allocated memory block back to a specific memory pool.
相關語法請參考 : MemoryPool。
Mail
的功能即是將上述的 Queue
和 Memory pool
功能整合起來。
以下為 Mail
的示意圖 :
以下為 Mail
的範例程式 :
#include "mbed.h"
#include "rtos.h"
/* Mail */
typedef struct {
float voltage; /* AD result of measured voltage */
float current; /* AD result of measured current */
uint32_t counter; /* A counter value */
} mail_t;
Mail<mail_t, 16> mail_box;
void send_thread (void) {
uint32_t i = 0;
while (true) {
i++; // fake data update
mail_t *mail = mail_box.alloc();
mail->voltage = (i * 0.1) * 33;
mail->current = (i * 0.1) * 11;
mail->counter = i;
mail_box.put(mail);
Thread::wait(1000);
}
}
int main (void) {
Thread thread;
thread.start(callback(send_thread));
while (true) {
osEvent evt = mail_box.get();
if (evt.status == osEventMail) {
mail_t *mail = (mail_t*)evt.value.p;
printf("\nVoltage: %.2f V\n\r" , mail->voltage);
printf("Current: %.2f A\n\r" , mail->current);
printf("Number of cycles: %u\n\r", mail->counter);
mail_box.free(mail);
}
}
}
常用指令 :
Mail< T, queue_sz > //Create and Initialise Mail queue.
Mail ()
T *alloc (uint32_t millisec=0) //Allocate a memory block of type T.
T *calloc (uint32_t millisec=0) //Allocate a memory block of type T and set memory block to zero.
osStatus put (T *mptr) //Put a mail in the queue.
osEvent get (uint32_t millisec=osWaitForever) //Get a mail from a queue.
osStatus free (T *mptr) //Free a memory block from a mai
相關語法請參考 : Mail。
The Status and Error Codes section lists all the return values that the CMSIS-RTOS functions
will return:
CMSIS-RTOS 是 ARM 公司為統一操作系統、降低嵌入式門檻而發佈的操作系統標準軟件接口。通俗講,CMSIS-RTOS 將操作系統(不管是 FREE-RTOS 還是 RTX 等)屏蔽起來,然後提供 CMSIS-RTOS 接口函數給最終用户調用。
osOK
: function completed ; no event occurred.osEventSignal
: function completed; signal event occurred.osEventMessage
: function completed; message event occurred.osEventMail
: function completed; mail event occurred.osEventTimeout
: function completed; timeout occurred.osErrorParameter
: parameter error: a mandatory parameter was missing or specified an incorrect object.osErrorResource
: resource not available: a specified resource was not available.osErrorTimeoutResource
: resource not available within given time : a specified resource was not available within the timeout period.osErrorISR
: not allowed in ISR context: the function cannot be called from interrupt service routines.osErrorISRRecursive
: function called multiple times from ISR with same object.osErrorPriority
: system cannot determine priority or thread has illegal priority.osErrorNoMemory
: system is out of memory: it was impossible to allocate or reserve memory for the operation.osErrorValue
: value of a parameter is out of range.osErrorOS
: unspecified RTOS error: run-time error but no other error message fits.※ 使用thread.terminate();使thread停止
請利用上述 RTOS 中的 Thread & Semaphore & Mutex來完成以下功能:
Learn More →
請利用上述 RTOS 中的 Mail 實現可繼續計時的碼表。 ※使用Thread::wait()計時