diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day2main.c" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day2main.c" new file mode 100644 index 0000000000000000000000000000000000000000..94fc0a78205c740d5cb2dcf1ee0c9228996f1e25 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day2main.c" @@ -0,0 +1,58 @@ +// 这里是第2天作业的代码 + +#include +#include +#include + +/** + * 定义三个函数用于创建线程 + * usr_thread_high_priority:高优先级线程用于实验抢占式调度 + * + * usr_thread_low_priority_1 + * usr_thread_low_priority_2:低优先级线程且优先级相同,用于实验时间片轮转的调度 + * + */ +void usr_thread_high_priority(void){ + while(1){ + for(int i = 0;i<10;i++){ + rt_kprintf("run in usr high priority\r\n"); + } + rt_thread_delay(100); // 主动释放CPU给时间让另外两个线程执行 + } +} + +void usr_thread_low_priority_1(void){ + while(1){ + rt_kprintf("run in usr low priority 1\r\n"); + } +} + +void usr_thread_low_priority_2(void){ + while(1){ + rt_kprintf("run in usr low priority 2\r\n"); + } +} + +rt_thread_t tid1 = RT_NULL; +rt_thread_t tid2 = RT_NULL; +rt_thread_t tid3 = RT_NULL; + +int main(void) { + // 创建并启动三个线程 + tid1 = rt_thread_create("usr1", usr_thread_high_priority, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY + 1, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + + tid2 = rt_thread_create("usr2", usr_thread_low_priority_1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY + 3, 5); + if(tid2 != RT_NULL){ + rt_thread_startup(tid2); + } + + tid3 = rt_thread_create("usr3", usr_thread_low_priority_2, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY + 3, 10); + if(tid2 != RT_NULL){ + rt_thread_startup(tid3); + } + + return RT_EOK; +} diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Event.c" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Event.c" new file mode 100644 index 0000000000000000000000000000000000000000..a0fc348b698404aff8149f6b9df39167cd482201 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Event.c" @@ -0,0 +1,67 @@ +#include +#include +#include + +#define EVENT_FLAG1 (1 << 1) +#define EVENT_FLAG2 (1 << 2) + +static rt_event_t event = RT_NULL; + +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + rt_uint32_t rcv; + rt_kprintf("waiting for event1 or event2"); + //以或的形式接收event1, event2 + if(rt_event_recv(event, (EVENT_FLAG1 | EVENT_FLAG2), + RT_EVENT_FLAG_OR, RT_WAITING_FOREVER, &rcv) == RT_EOK){ + rt_kprintf("usr1: OR receive event0x%x\n", rcv); + } + + rt_kprintf("waiting for event1 and event2\n"); + //以且的形式接收event1, event2 + if(rt_event_recv(event, (EVENT_FLAG1 | EVENT_FLAG2), + RT_EVENT_FLAG_AND, RT_WAITING_FOREVER, &rcv) == RT_EOK){ + rt_kprintf("usr1: AND receive event0x%x\n", rcv); + } + rt_event_delete(event); + rt_kprintf("end\n"); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + rt_kprintf("event1 sent\n"); + rt_event_send(event, EVENT_FLAG1); +} + +void usr_thread3(void){ + rt_kprintf("run usr3\n"); + rt_kprintf("event2 sent\n"); + rt_event_send(event, EVENT_FLAG2); +} + +rt_thread_t tid1 = RT_NULL; +rt_thread_t tid2 = RT_NULL; +rt_thread_t tid3 = RT_NULL; + +int main(void) { + // 创建事件集 + event = rt_event_create("event1", RT_IPC_FLAG_PRIO); + + // 创建三个线程 + tid1 = rt_thread_create("usr1", usr_thread1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 3, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + + tid2 = rt_thread_create("usr2", usr_thread2, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 2, 5); + if(tid2 != RT_NULL){ + rt_thread_startup(tid2); + } + + tid3 = rt_thread_create("usr3", usr_thread3, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 1, 5); + if(tid3 !=RT_NULL){ + rt_thread_startup(tid3); + } + + return RT_EOK; +} diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Mailbox.c" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Mailbox.c" new file mode 100644 index 0000000000000000000000000000000000000000..d249302786c05c74745b435f3b305ebfd2ea692a --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Mailbox.c" @@ -0,0 +1,46 @@ +#include +#include +#include + +static rt_mailbox_t mb = RT_NULL; + +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + int recv = 0; + while(recv<9){ + if(rt_mb_recv(mb, (rt_ubase_t*)&recv, RT_WAITING_FOREVER) == RT_EOK){ + rt_kprintf("usr1: get a mail from mailbox, content:%d\n",recv); + } + } + rt_mb_delete(mb); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + for(int i = 0;i<10;i++){ + rt_kprintf("usr2 send a mail, content:%d\n",i); + rt_mb_send(mb, (rt_uint32_t)i); + rt_thread_mdelay(50); + } +} + +rt_thread_t tid1 = RT_NULL; +rt_thread_t tid2 = RT_NULL; + +int main(void) { + //创建邮箱 + mb = rt_mb_create("mb1", 10, RT_IPC_FLAG_PRIO); + + //启动两个线程 + tid1 = rt_thread_create("usr1", usr_thread1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 2, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + + tid2 = rt_thread_create("usr2", usr_thread2, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 2, 5); + if(tid2 != RT_NULL){ + rt_thread_startup(tid2); + } + + return RT_EOK; +} diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3MessageQueue.c" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3MessageQueue.c" new file mode 100644 index 0000000000000000000000000000000000000000..851919b10b0bcb510d7ddd1499044dae24806a4d --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3MessageQueue.c" @@ -0,0 +1,54 @@ +#include +#include +#include + +static rt_mq_t mq = RT_NULL; + +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + int recv = 0; + //接收10个数字 + while(recv<9){ + if(rt_mq_recv(mq, &recv, sizeof(recv), RT_WAITING_FOREVER) == RT_EOK){ + rt_kprintf("usr1: get a msg from msgq, content:%d\n",recv); + } + rt_thread_mdelay(50); + } + rt_mq_delete(mq); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + //发送10个数字,5为紧急消息。 + for(int i = 0;i<10;i++){ + if(i != 5){ + rt_kprintf("usr2 send a msg, content:%d\n",i); + rt_mq_send(mq, &i, sizeof(i)); + }else{ + rt_kprintf("usr2 send an urgent msg, content:%d\n",i); + rt_mq_urgent(mq, &i, sizeof(i)); + } + rt_thread_mdelay(9); + } +} + +rt_thread_t tid1 = RT_NULL; +rt_thread_t tid2 = RT_NULL; + +int main(void) { + // 创建一个消息队列 + mq = rt_mq_create("msgq1", sizeof(int), 10, RT_IPC_FLAG_PRIO); + + //创建两个线程 + tid1 = rt_thread_create("usr1", usr_thread1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 2, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + + tid2 = rt_thread_create("usr2", usr_thread2, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 2, 5); + if(tid2 != RT_NULL){ + rt_thread_startup(tid2); + } + + return RT_EOK; +} diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Mutex.c" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Mutex.c" new file mode 100644 index 0000000000000000000000000000000000000000..75c9110c8f34b9d421cd60eaca9323241ec50c72 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Mutex.c" @@ -0,0 +1,61 @@ +#include +#include +#include + +static rt_mutex_t mutex = RT_NULL; +static rt_uint8_t count = 0, cycle = 10; + +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + while(cycle > 0){ + count = 0; + //申请互斥量 + rt_mutex_take(mutex, RT_WAITING_FOREVER); + rt_kprintf("usr1 message1\n"); + ++count; + rt_thread_mdelay(50);//让出CPU + rt_kprintf("usr1 message2\n"); + ++count; + //释放互斥量 + rt_mutex_release(mutex); + + --cycle; + } +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + while(1){ + //申请互斥量 + rt_mutex_take(mutex, RT_WAITING_FOREVER); + if(count&0x1){ + rt_kprintf("single message detect\n"); + }else{ + rt_kprintf("double message print\n"); + } + //释放互斥量 + rt_mutex_release(mutex); + if(cycle == 0)break;//打印完毕退出 + } + rt_mutex_delete(mutex); +} + +rt_thread_t tid1 = RT_NULL; +rt_thread_t tid2 = RT_NULL; + +int main(void) { + //创建互斥量 + mutex = rt_mutex_create("mutex1", RT_IPC_FLAG_PRIO); + + tid1 = rt_thread_create("usr1", usr_thread1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 1, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + + tid2 = rt_thread_create("usr2", usr_thread2, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 1, 5); + if(tid2 != RT_NULL){ + rt_thread_startup(tid2); + } + + return RT_EOK; +} diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Semaphore.c" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Semaphore.c" new file mode 100644 index 0000000000000000000000000000000000000000..cdb44b327666b639f4ede00ec09735a623da7ec1 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Semaphore.c" @@ -0,0 +1,47 @@ +#include +#include +#include + +static rt_sem_t sem1 = RT_NULL; + +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + // 尝试获取信号量 + if(rt_sem_take(sem1, RT_WAITING_FOREVER) != RT_EOK){ + rt_kprintf("usr1 take sem faild\n"); + }else{ + rt_kprintf("usr1 run later\n"); + } + rt_sem_delete(sem1); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + rt_kprintf("usr2 delay 30ms\n"); + rt_thread_mdelay(30); + rt_kprintf("usr2 run first then release semaphore\n"); + // 释放信号量 + rt_sem_release(sem1); +} + +rt_thread_t tid1 = RT_NULL; +rt_thread_t tid2 = RT_NULL; + +int main(void) { + //创建同步信号量 + sem1 = rt_sem_create("sem1", 0, RT_IPC_FLAG_PRIO); + + //创建线程1,优先级较高,先执行 + tid1 = rt_thread_create("usr1", usr_thread1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 3, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + + // 创建线程2,优先级较低,后执行 + tid2 = rt_thread_create("usr2", usr_thread2, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 1, 5); + if(tid2 != RT_NULL){ + rt_thread_startup(tid2); + } + + return RT_EOK; +} \ No newline at end of file diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Signal.c" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Signal.c" new file mode 100644 index 0000000000000000000000000000000000000000..48f7b4a23eac9a78583cdd1be0b7401004d601a9 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/Day3Signal.c" @@ -0,0 +1,33 @@ +#include +#include +#include + +//handle回调函数 +void usr_thread1_handler(int signal){ + rt_kprintf("handle signal %d\n", signal); +} + +void usr_thread1(void){ + //安装并响应信号 + rt_signal_install(SIGUSR1, usr_thread1_handler); + rt_signal_unmask(SIGUSR1); + for(int i = 0;i < 10;i++){ + rt_kprintf("waiting for kill %d\n", i); + rt_thread_mdelay(50); + } +} + +rt_thread_t tid1 = RT_NULL; + +int main(void){ + //创建线程 + tid1 = rt_thread_create("usr1", usr_thread1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 2, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + rt_thread_mdelay(300); + //向线程发送信号 + rt_thread_kill(tid1, SIGUSR1); + + return RT_EOK; +} diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day2/polling.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day2/polling.png" new file mode 100644 index 0000000000000000000000000000000000000000..591df48a63a051d3aa645e0f39ac20a73d28568a Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day2/polling.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day2/preemptive.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day2/preemptive.png" new file mode 100644 index 0000000000000000000000000000000000000000..2c8f03639e21af81dc8b7f3f4b05e91aad6dc676 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day2/preemptive.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/event.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/event.png" new file mode 100644 index 0000000000000000000000000000000000000000..3cf60bd5eb6a25b0b7915f1399ea7193ac7f00e0 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/event.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/mailbox.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/mailbox.png" new file mode 100644 index 0000000000000000000000000000000000000000..01dd2c46981ab341dee9cb94c74bd0f8fabdfadf Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/mailbox.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/msgq.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/msgq.png" new file mode 100644 index 0000000000000000000000000000000000000000..6de715664e4870a69aa7d8a60815d242d18cc9b5 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/msgq.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/mutex.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/mutex.png" new file mode 100644 index 0000000000000000000000000000000000000000..514f9594752d9bb5f132b9235a88d5889f9f3a24 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/mutex.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/semaphore.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/semaphore.png" new file mode 100644 index 0000000000000000000000000000000000000000..c795f4f8f0b2a5009efd7efdcbf89730fbaaf9a5 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/semaphore.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/signal.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/signal.png" new file mode 100644 index 0000000000000000000000000000000000000000..cdc827e9dbc047a41b9939a2bccdcf3a35e99329 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/figures/day3/signal.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2541\345\244\251\344\275\234\344\270\232.md" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2541\345\244\251\344\275\234\344\270\232.md" new file mode 100644 index 0000000000000000000000000000000000000000..3b220eb0a241a33aaa831a4217b79291ad9989c9 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2541\345\244\251\344\275\234\344\270\232.md" @@ -0,0 +1,5 @@ +## 针对qemu平台的项目编译 +已经写在[第1天笔记](../笔记/第1天笔记.md#尝试针对qemu平台编译)中了,此处不再赘述。 + +## 整理并提交笔记 +详见夏令营仓库的[PR列表](https://gitee.com/rtthread/rsoc-rtt/pulls)及[夏令营作业收集表](https://docs.qq.com/sheet/DSkFwaW9GZVpYY0VI?tab=BB08J2) \ No newline at end of file diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2542\345\244\251\344\275\234\344\270\232.md" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2542\345\244\251\344\275\234\344\270\232.md" new file mode 100644 index 0000000000000000000000000000000000000000..546bba897fa0828f599930b6ded5be816529a995 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2542\345\244\251\344\275\234\344\270\232.md" @@ -0,0 +1,38 @@ +## 线程设计 +一个高优先级线程用于实验抢占式调度 + +```c +void usr_thread_high_priority(void){ + while(1){ + for(int i = 0;i<10;i++){ + rt_kprintf("run in usr high priority\r\n"); + } + rt_thread_delay(100); // 主动释放CPU给时间让另外两个线程执行 + } +} +``` + +两个低优先级的线程用于实验时间片轮转调度 + +```c +void usr_thread_low_priority_1(void){ + while(1){ + rt_kprintf("run in usr low priority 1\r\n"); + } +} + +void usr_thread_low_priority_2(void){ + while(1){ + rt_kprintf("run in usr low priority 2\r\n"); + } +} +``` + +详细实现见[Day2main.c](Day2main.c) + +## 实验结果 +抢占式 +![preemptive](figures/day2/preemptive.png) + +时间片轮询 +![polling](figures/day2/polling.png) \ No newline at end of file diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2543\345\244\251\344\275\234\344\270\232.md" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2543\345\244\251\344\275\234\344\270\232.md" new file mode 100644 index 0000000000000000000000000000000000000000..1b1f3696a833c28c0d67b1db6dbcf657fd9a4c53 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\344\275\234\344\270\232/\347\254\2543\345\244\251\344\275\234\344\270\232.md" @@ -0,0 +1,219 @@ +## 信号量semaphore +### 线程设计 +设计两个线程,让低优先级的线程释放信号量,高优先级的线程获得信号量,从而保证低优先级的线程先执行。 +```c +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + // 尝试获取信号量 + if(rt_sem_take(sem1, RT_WAITING_FOREVER) != RT_EOK){ + rt_kprintf("usr1 take sem faild\n"); + }else{ + rt_kprintf("usr1 run later\n"); + } + rt_sem_delete(sem1); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + rt_kprintf("usr2 delay 30ms\n"); + rt_thread_mdelay(30); + rt_kprintf("usr2 run first then release semaphore\n"); + // 释放信号量 + rt_sem_release(sem1); +} +``` +详细代码查看[Day3Semaphore](Day3Semaphore.c) +### 运行结果 +![信号量](figures/day3/semaphore.png) + +## 互斥量mutex +### 线程设计 +设计两个线程,相同优先级,一个线程会依次打印两条信息,但打印之间会delay,使用互斥量防止打印一次时被检测。线程2检测是否打印了单条信息。 +```c +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + while(cycle > 0){ + count = 0; + //申请互斥量 + rt_mutex_take(mutex, RT_WAITING_FOREVER); + rt_kprintf("usr1 message1\n"); + ++count; + rt_thread_mdelay(50);//让出CPU + rt_kprintf("usr1 message2\n"); + ++count; + //释放互斥量 + rt_mutex_release(mutex); + + --cycle; + } +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + while(1){ + //申请互斥量 + rt_mutex_take(mutex, RT_WAITING_FOREVER); + if(count&0x1){ + rt_kprintf("single message detect\n"); + }else{ + rt_kprintf("double message print\n"); + } + //释放互斥量 + rt_mutex_release(mutex); + if(cycle == 0)break;//打印完毕退出 + } + rt_mutex_delete(mutex); +} +``` +详细代码查看[Day3Mutex](Day3Mutex.c) + +### 运行结果 +![互斥量](figures/day3/mutex.png) + +## 事件集event +### 线程设计 +设计三个线程,两个低优先级的线程分别发出两个事件,一个高优先级的线程接收事件。 +```c +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + rt_uint32_t rcv; + rt_kprintf("waiting for event1 or event2"); + //以或的形式接收event1, event2 + if(rt_event_recv(event, (EVENT_FLAG1 | EVENT_FLAG2), + RT_EVENT_FLAG_OR, RT_WAITING_FOREVER, &rcv) == RT_EOK){ + rt_kprintf("usr1: OR receive event0x%x\n", rcv); + } + + rt_kprintf("waiting for event1 and event2\n"); + //以且的形式接收event1, event2 + if(rt_event_recv(event, (EVENT_FLAG1 | EVENT_FLAG2), + RT_EVENT_FLAG_AND, RT_WAITING_FOREVER, &rcv) == RT_EOK){ + rt_kprintf("usr1: AND receive event0x%x\n", rcv); + } + rt_event_delete(event); + rt_kprintf("end\n"); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + rt_kprintf("event1 sent\n"); + rt_event_send(event, EVENT_FLAG1); +} + +void usr_thread3(void){ + rt_kprintf("run usr3\n"); + rt_kprintf("event2 sent\n"); + rt_event_send(event, EVENT_FLAG2); +} +``` +详细代码查看[Day3Event](Day3Event.c) + +### 运行结果 +![事件集](figures/day3/event.png) + +## 邮箱mailbox +### 线程设计 +设计两个线程,一个发送数字,一个接收数字 +```c +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + int recv = 0; + //循环接收数字 + while(recv<9){ + if(rt_mb_recv(mb, (rt_ubase_t*)&recv, RT_WAITING_FOREVER) == RT_EOK){ + rt_kprintf("usr1: get a mail from mailbox, content:%d\n",recv); + } + } + rt_mb_delete(mb); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + //发送数字1-9 + for(int i = 0;i<10;i++){ + rt_kprintf("usr2 send a mail, content:%d\n",i); + rt_mb_send(mb, (rt_uint32_t)i); + rt_thread_mdelay(50); + } +} +``` +详细代码查看[Day3Mailbox](Day3Mailbox.c) + +### 运行结果 +![邮箱](figures/day3/mailbox.png) + +## 消息队列message_queue +### 线程设计 +设计两个线程,一个线程发送数字,同时夹杂一个紧急信息,另一个线程接收数字。 +```c +void usr_thread1(void){ + rt_kprintf("run usr1\n"); + int recv = 0; + //接收10个数字 + while(recv<9){ + if(rt_mq_recv(mq, &recv, sizeof(recv), RT_WAITING_FOREVER) == RT_EOK){ + rt_kprintf("usr1: get a msg from msgq, content:%d\n",recv); + } + rt_thread_mdelay(50); + } + rt_mq_delete(mq); +} + +void usr_thread2(void){ + rt_kprintf("run usr2\n"); + //发送10个数字,5为紧急消息。 + for(int i = 0;i<10;i++){ + if(i != 5){ + rt_kprintf("usr2 send a msg, content:%d\n",i); + rt_mq_send(mq, &i, sizeof(i)); + }else{ + rt_kprintf("usr2 send an urgent msg, content:%d\n",i); + rt_mq_urgent(mq, &i, sizeof(i)); + } + rt_thread_mdelay(9); + } +} +``` +详细代码查看[Day3MessagQueue](Day3MessageQueue.c) + +### 运行结果 +![消息队列](figures/day3/msgq.png) + +## 信号signal +### 线程设计 +设计一个线程,main函数对其发送信号,由该线程处理 +```c +//handle回调函数 +void usr_thread1_handler(int signal){ + rt_kprintf("handle signal %d\n", signal); +} + +void usr_thread1(void){ + //安装并响应信号 + rt_signal_install(SIGUSR1, usr_thread1_handler); + rt_signal_unmask(SIGUSR1); + for(int i = 0;i < 10;i++){ + rt_kprintf("waiting for kill %d\n", i); + rt_thread_mdelay(50); + } +} + +rt_thread_t tid1 = RT_NULL; + +int main(void){ + //创建线程 + tid1 = rt_thread_create("usr1", usr_thread1, RT_NULL, 1024, RT_MAIN_THREAD_PRIORITY - 2, 5); + if(tid1 != RT_NULL){ + rt_thread_startup(tid1); + } + rt_thread_mdelay(300); + //向线程发送信号 + rt_thread_kill(tid1, SIGUSR1); + + return RT_EOK; +} +``` +详细代码查看[Day3Signal](Day3Signal.c) + +### 运行结果 +![消息队列](figures/day3/signal.png) diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/compile_1.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/compile_1.png" new file mode 100644 index 0000000000000000000000000000000000000000..a80eee2dc6278b6d7f5e60ab4fe55a3cd8f48268 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/compile_1.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/compile_2.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/compile_2.png" new file mode 100644 index 0000000000000000000000000000000000000000..18554ad97a39f7771f2f140d0b525935f6af8186 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/compile_2.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/boot.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/boot.png" new file mode 100644 index 0000000000000000000000000000000000000000..cab5f198c08ccff8891d00fcf331a13cce911898 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/boot.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/entry.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/entry.png" new file mode 100644 index 0000000000000000000000000000000000000000..df40cd0f0fab96b173c4186289f7936b7705eecc Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/entry.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/install_packages.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/install_packages.png" new file mode 100644 index 0000000000000000000000000000000000000000..5c7043943fbb7ec36db61590308a139b5e542b44 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/install_packages.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project0.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project0.png" new file mode 100644 index 0000000000000000000000000000000000000000..629449d465125f44afcbc89f47a4afa656fc8c32 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project0.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_code.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_code.png" new file mode 100644 index 0000000000000000000000000000000000000000..4544cc66baac5481d69cd29049b27e511827bead Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_code.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_config.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_config.png" new file mode 100644 index 0000000000000000000000000000000000000000..790a956a9cf6f49addf8e441338dbcc9663c1201 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_config.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_run.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_run.png" new file mode 100644 index 0000000000000000000000000000000000000000..d68e0176e5add0b6fe9d987656cf3edb203c67c9 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/project1_run.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/rtt_startup.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/rtt_startup.png" new file mode 100644 index 0000000000000000000000000000000000000000..04dbb79fed05b7463c5ceea179f5dd75c6553724 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/rtt_startup.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/runtime_status.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/runtime_status.png" new file mode 100644 index 0000000000000000000000000000000000000000..58564d0e8c0e5b9a911b83bd7fb8b3e4578a58d4 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/runtime_status.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/schedule.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/schedule.png" new file mode 100644 index 0000000000000000000000000000000000000000..5f547a334772280faa91dac3bbfe7b4f15747b3c Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/schedule.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/stack_frame.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/stack_frame.png" new file mode 100644 index 0000000000000000000000000000000000000000..7d544624d4230d294145f8121a4761ba9f951dcd Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/stack_frame.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/startup.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/startup.png" new file mode 100644 index 0000000000000000000000000000000000000000..b464afed48f85bbdc1b6d86cfb3f3cdc5a360803 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/startup.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/studio_ui.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/studio_ui.png" new file mode 100644 index 0000000000000000000000000000000000000000..83dacdd58b97b3c023b69928a5858687503ff39b Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day2/studio_ui.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/count_sample.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/count_sample.png" new file mode 100644 index 0000000000000000000000000000000000000000..5a69a8108857665bb5a2ac21ad6693297987bf37 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/count_sample.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/event_sample.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/event_sample.png" new file mode 100644 index 0000000000000000000000000000000000000000..152d02fd942215f3ab19f9564d9b266a13ed7ac6 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/event_sample.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/mainbox.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/mainbox.png" new file mode 100644 index 0000000000000000000000000000000000000000..fd12377fa701ab5f8ff580cc004e260268731967 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/mainbox.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/msg_queue.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/msg_queue.png" new file mode 100644 index 0000000000000000000000000000000000000000..f9f7ad68f3d9caa955066c9a5480d4ea3ff1c1a1 Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/msg_queue.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/sync_sample.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/sync_sample.png" new file mode 100644 index 0000000000000000000000000000000000000000..19b22d08a901d3665ca31ac002d8ddd4341f28de Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/day3/sync_sample.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/gui.png" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/gui.png" new file mode 100644 index 0000000000000000000000000000000000000000..575ba006d67c2109067fca506b9215c04e4586ac Binary files /dev/null and "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/figures/gui.png" differ diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2541\345\244\251\347\254\224\350\256\260.md" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2541\345\244\251\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..9b979a22e90989a2a961fd8d3158580b511469d6 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2541\345\244\251\347\254\224\350\256\260.md" @@ -0,0 +1,124 @@ +## 环境搭建与测试 + +### Git +安装版本管理软件[Git](https://git-scm.com/downloads)用于项目源代码仓库的管理和版本控制。 + +### 拉取RT-Thread项目源码 +从[github(国外)](https://github.com/RT-Thread/rt-thread)或[gitee(国内)](https://gitee.com/rtthread/rt-thread)代码仓库获取源码,使用命令 + +```sh +git clone https://gitee.com/rtthread/rt-thread.git +``` + +### 安装env工具 +从[github仓库](https://github.com/RT-Thread/env-windows)、[gitee仓库](https://gitee.com/mirrors_RT-Thread/env-windows)拉取或[官网](https://www.rt-thread.org/download.html)下载,官网的为离线版本,且版本号更新一点。其中使用了sub module,使用以下命令拉取 + +```sh +git clone --recursive --depth 1 https://github.com/RT-Thread/env-windows.git + +git clone --recursive --depth 1 https://gitee.com/mirrors_RT-Thread/env-windows.git +``` + +打开目录下的 `env.bat` 文件等待环境配置完成。 + +在命令窗口的右上角 `settings -> Integration -> Register` 将 `env` 注册到Windows右键菜单中。方便之后在对应目录打开 `env` + +先进行一次 `menuconfig` 生成配置文件,直接保存退出。 + +使用以下命令更新 +```sh +pkgs --update #更新包 + +pkgs --upgrade #更新env +``` + +可以使用 `help` 命令查看所有命令 + +### RT-Thread目录结构 +|名称 |描述 | +|-------------|---------------------------------------------------| +|bsp |Board Support Package(板级支持包)基于各种开发板的移植| +|components |RT-Thread 的各个组件代码,例如 finsh,gui 等。 | +|documentation|相关文档,如编码规范等 | +|examples |相关示例代码 | +|include |RT-Thread 内核的头文件。 | +|libcpu |各类芯片的移植代码。 | +|src |RT-Thread 内核的源文件。 | +|tools |RT-Thread 命令构建工具的脚本文件。 | + +### 尝试针对qemu平台编译 +在 `rt-thread\bsp\qemu-vexpress-a9` 目录下打开 `env` 工具,并使用menuconfig生成配置文件,直接保存退出即可。 + +使用以下命令编译,其中的数字表示编译使用的线程数。最终编译生成elf文件。 +```sh +scons -j4 #编译 +scons -c #清除编译文件 +``` + +![编译](figures/compile_1.png) + +使用以下命令启动,进入shell界面 +```sh +qemu-nographic.bat +``` + +在shell界面可以使用以下命令 +```sh +list device #查看当前所有的设备 +list thread #查看当前启动的线程 +list timer #当前使用到的定时器 +Ctrl+A松开后再按X #退出终端 +``` +尝试修改 `applications` 目录下的 `main.c` 文件后重新编译运行。 +![修改main后重新编译](figures/compile_2.png) + +### 编译过程概述 +项目的编译依赖于python脚本包括项目根目录的 `SConstruct` 、 `SConscript` 文件 以及各个目录下的`SConscript` 文件,通过递归查找目录下的 `.c` 和 `.cpp` 文件并返回,最终形成编译命令。 + +### 重新配置项目实现图像显示 +在 `rt-thread\bsp\qemu-vexpress-a9` 目录下打开 `env` 工具,并使用menuconfig生成配置文件,打开 `Hardware Drivers Config -> Onboard Peripheral Drivers -> Enable LVGL for LCD` 返回保存,更新 `Kconfig` 文件,同时会同步到 `.config` 文件中并生成 `rtconfig.h` 文件。 + +LVGL是一个软件包使用 `pkgs --update` 。实际上在保存退出后就会默认进行下载。下载的文件在根目录packages文件夹下。 + +再次编译生成elf文件并使用以下命令启动带有图形界面的终端。 +```sh +qemu.bat +``` +![图形界面](figures/gui.png) + + +### 安装VSCode +在[官网](https://code.visualstudio.com/)安装VSCode用于编辑代码及后续调试等 + +## Git使用及提交PR +Git主要用于项目的版本管理及多人协作。 + +### .git文件夹 +项目根目录下有.git文件夹,其中存储了和git 相关的文件,包括历史记录及一些配置主要的配置可以在 `config` 文件中查看。 + +### 常用命令 +```sh +git init #初始化文件夹成为一个git仓库 +git status #查看当前状态 +git add #暂存文件,将文件放到暂存区 +git log #查看历史 +git switch #切换分支 +git checkout #回退,迁出分支 +git reset --soft/--hard HEAD~ #重置,soft保留操作到暂存区hard直接删除 +git branch/checkout -b #创建新的分支 +git commit -m "本次提交说明" #提交代码 +git merge #合并分支 +``` + +### 使用ssh拉取仓库 +在第一次使用时需要创建一对密钥完成ssh配置(gitee平台) +```sh +ssh-keygen -t rsa #创建密钥对 +``` +windows环境下使用OpenSSH密钥对默认的存储位置为 `C:/Users/UserName/.ssh/` 默认文件名称为 `id_rsa(私钥)` 和 `id_rsa.pub(公钥)` 生成密钥时最好不要修改名称,修改名称会涉及到配置该目录下的 `config` 文件。使用以下命令测试配置正确性。 +```sh +ssh -T git@gitee.com +``` + +### 提交PR +首先对目标仓库进行 `fork` 操作将其拷贝到自己的仓库。本地完成编辑之后推送到自己的仓库。最后在目标仓库的PR列表提交PR请求。 \ No newline at end of file diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2542\345\244\251\347\254\224\350\256\260.md" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2542\345\244\251\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..71fbcd99954a90d22c7995db43a234338e237f10 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2542\345\244\251\347\254\224\350\256\260.md" @@ -0,0 +1,129 @@ +## RT-Thread内核基础与线程 + +### 裸机与RTOS +功能单一的情况下,系统整体功能没有细分多个线程的必要,采用裸机较为合适。例如电动牙刷 + +系统功能丰富情况下,使用裸机编程需要编写复杂的逻辑协调多个事件,同时代码的耦合度较高,采用RTOS较为合适。例如机器人。 + +裸机优点与缺点: +- 单一功能的嵌入式系统使用裸机可以提高运行效率 +- 可以使用较少的存储实现单一功能的嵌入式系统 +- 代码耦合度较高,复用性差 +- 不适合复杂的嵌入式系统 +- 代码不合理时容易造成系统阻塞 + +RTOS优点与缺点: +- 代码耦合度低,复用性好 +- 可以使用任务划分的方式降低实现复杂嵌入式操作系统的代码逻辑 +- 延时操作不会一直占用CPU,延时期间处理其他任务 +- 使用RTOS提供的线程同步与信息传递会提高系统的实时性 +- 不适合小容量嵌入式系统,RTOS本身会占据部分存储 +- 不适合单一嵌入式系统,系统调度会引入额外的开销 + +> RTOS编程的思想为模块化“分而治之”的拆分思想,降低每个任务的复杂性。 + +下图为两种程序的运行情况 +![运行情况](figures/day2/runtime_status.png) + +### 临界区 +临界区的资源在同一时间只能被一个线程使用,一但临界资源被占用,其他线程只能等待。 + +一个线程先占用了临界区的资源,其他线程想使用临界资源就必须等待,这种阻塞其他线程继续执行的情况就是线程阻塞(Blocking) + +### 系统启动 +如下图为RT-Thread的系统启动过程 +![启动过程](figures/day2/rtt_startup.png) + +其中启动文件 `startup_xx.S` 对flash、ram等硬件介质进行初始化。之后根据不同的编译环境(MDK、IAR、GCC)进入不同的函数。如图为STM32F407的板级开发包,其中的启动文件中调用了entry函数。 +![启动文件](figures/day2/startup.png) + +而在 `component.c` 文件中又根据不同的编译环境分别写了预编译命令。如图中框出的为gcc环境下的entry函数,其中调用了又调用了 `rtthread_startup` 函数。 +![entry](figures/day2/entry.png) + +在 `rtthread_startup` 中首先进行了关中断的操作 `rt_hw_interrupt_disable`,避免外部的中断打断操作系统的初始化。 + +`rt_hw_board_init` 进行一些板级外设硬件的初始化。初始化外设之后就可以通过 `rt_show_version` 从串口打印信息。 + +对于 `rt_system_timer_init` 和 `rt_system_timer_thread_init` 他们用于初始化系统中的定时器。前者是系统中使用硬件中断计时的,后者是软件定时器对线程进行计时,前者的精度更高。 + +`rt_system_scheduler_init` 用于初始化调度器的队列 + +`rt_system_signal_init` 软件中断的初始化 + +`rt_application_init` 和 `rt_thread_idle_init` 后者创建了一个空闲线程,若系统中没有要运行的线程,则调度空闲线程,它是优先级最低的一个线程它永远处于就绪状态不会被挂起。其中适合使用一些钩子函数进行功耗管理看门狗喂狗等操作。前者创建main函数的线程。 + +`rt_system_scheduler_start` 启动系统开始进行线程调度。在main函数执行之前还有一部分软件初始化,如协议栈、驱动、软件包等的初始化。 + +### 线程调度 +若某线程运行完毕,系统将自动删除线程:自动执行 `rt_thread_exit` 函数,先将该线程从系统就绪队列中删除,再将该线程的状态更改为关闭,不再参与系统调度,然后挂入 `rt_thread_defunct` 僵尸队列(资源未回收、处于关闭状态的线程队列),最后空闲线程会回收被删除线程的资源。 + +### 线程创建 +一个线程要成为可执行的对象,就必须由操作系统的内核来为它创建一个线程,可以通过一下接口创建一个动态线程。 +```c +rt_thread_t rt_thread_create(const char*name, + void (*entry)(void* parameter), + void* parameter, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick); +``` +其中参数 `name` 用于找到线程的控制块,最终获得句柄,通过句柄获得线程的状态等信息。 `priority` 是优先级,数字越小优先级越高。 `tick` 是时间片大小。 + +调用此函数时,系统从动态堆内存中分配一个线程句柄以及按照参数中指定的栈大小相应的空间。分配出来的栈空间按照 `rtconfig.h` 中配置的 `RT_ALIGN_SIZE` 方式对齐。 + +创建线程还可以使用函数 `rt_thread_init` 创建线程,两者区别在于此函数是静态创建线程,而create函数是动态创建线程。静态创建在编译阶段就分配了空间,只为此线程使用更安全,无论后续线程处于什么状态都不会给其他线程使用。系统的几乎所有线程都是静态分配的。动态创建使用动态分配的方式分配空间,后续可以回收。使用init创建的线程使用函数 `rt_thread_detach` 进行分离(从就绪队列移除),使用create创建的函数则用函数 `rt_thread_delete` 释放空间。 + +### 其他线程相关函数 +`rt_thead_self` 获取当前运行的线程 +`rt_thead_find` 通过名称寻找线程控制块 +`rt_thead_startup` 启动线程进入就绪状态(创建后状态处于初始状态还未加入调度) +`rt_thead_yield` 立刻放弃当前线程的时间片 +`rt_thead_delay` 延时,主动释放CPU +`rt_thead_control` 修改线程的优先级等控制信息 +`rt_thead_suspend` 挂起线程,只能对自己线程操作 +`rt_thead_resume` 恢复线程 + +### 线程创建的一些原理 +两种创建都调用了函数 `_thread_init` 该函数除了进行回调函数的初始化之外还调用了一个重要的函数 `rt_hw_stack_init` 其中对栈帧进行了初始化。由于该线程还未被调用初始化栈帧实际相当于手动设置了现场。 + +栈帧结构体 `stack_frame` 其中又包含了一个结构体 `exception_stack_frame`。他们的区别涉及到调用约定。如下图,其中红色的为被调用者保存寄存器,需要被调用函数保存/恢复。绿色中的r0-r3是调用者保存寄存器,函数调用时进行临时传参。此规定与具体芯片有关。此外由于Cortex-M3/M4支持硬件压栈、恢复, `exception_stack_frame` 中的寄存器可以由硬件自动保存,而 `stack_frame` 中的其他寄存器就需要操作系统手动保存。 +![stack_frame](figures/day2/stack_frame.png) + +此外创建线程中还初始化了定时器,用于线程中的delay操作。 + +### 线程状态的转化 +![线程状态转化](figures/day2/schedule.png) + +无循环的线程执行完毕后系统自动回收资源,循环的线程会通过系统延时主动让出CPU或等待IPC。 + +### 调度器的工作 +- 优先级抢占:保证一个最高优先级的任务运行,从就绪链表中查找最高优先级的任务。 +- 时间片轮转:相同优先级状态下根据时间片轮转运行。 + +## RT-Thread Studio简单示例 +首先安装[RT-Thread Studio](https://www.rt-thread.org/studio.html) + +其中主要需要的功能如下图所示 +![studio_ui](figures/day2/studio_ui.png) + +此示例主要针对stm32F407板级开发包。 + +### stm32F407板级开发包安装 +首先在SDK管理中勾选 `Board_Support_Packages/STMicroelectronics/STM32F407-ATK-EXPLORE` 的最新版以及 `Debuger_Support_Packages/QEMU` 的最新版,并安装资源包。 +![安装资源包](figures/day2/install_packages.png) + +之后新建RT-Thread项目,选择基于开发版,选中刚下载的开发板及调试器和对应的模拟器。创建工程后选中项目处于激活状态并编译项目。编译成功后点击下载按钮选择对应的模拟器运行代码,进入msh。 +![项目0](figures/day2/project0.png) + +### 安装线程软件包 +在工程目录下的 `RT-Thread Settings` 中打开 `软件包 -> 杂项软件包 -> 软件包内核示例/thread` 再按Ctrl+S保存完成软件包的拉取与配置。 +![项目1配置](figures/day2/project1_config.png) + +编译运行后在shell运行 `thread_sample` 查看示例 +![项目1运行](figures/day2/project1_run.png) + +可以看到代码中分别通过动态和静态的方式创建了共2个线程。 +![项目1代码](figures/day2/project1_code.png) + +### 编写代码体现抢占与时间片轮转 +详见[第2天作业](../作业/第2天作业.md) \ No newline at end of file diff --git "a/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2543\345\244\251\347\254\224\350\256\260.md" "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2543\345\244\251\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..5450bb78ed6d08bdb0ef983451b92a5345a101f5 --- /dev/null +++ "b/2025/\347\254\2544\347\273\204(FRDM-MCXA156)/\346\235\234\346\265\251\347\204\266/\347\254\224\350\256\260/\347\254\2543\345\244\251\347\254\224\350\256\260.md" @@ -0,0 +1,282 @@ +# IPC机制 +RT-Thread的IPC机制分为线程同步和线程间通信。 + +线程同步有以下机制 +- 信号量(Semaphore) +- 互斥量(Mutex) +- 事件集(Event) + +线程间通信有以下机制 +- 邮箱(mailbox) +- 消息队列(msgqueue) + +## 线程间同步 +### 信号量 +信号量(Semaphore)是一种轻型的用于解决线程间同步问题的内核对象,一个或多个运行线程可以获取或释放它,从而达到同步或互斥的目的。用于实现任务与任务之间、任务与中断程序之间的同步与互斥。 + +信号量一般分为三种 +- 互斥信号量:解决互斥问题。但可能引起优先级反转的问题,因此一般不使用 +- 二值信号量:解决同步问题。 +- 计数信号量:解决资源计数问题。 + +二值信号量主要用于线程与线程之间、线程与中断服务程序(ISR)之间的同步。用于同步分二值信号量初始值为0,表示同步事件尚未产生。一个线程获取信号量等待事件发生,另一个线程或ISR到达同步点时释放信号量,从而唤醒等待的任务。信号量为0时不可获得,为1时可以获得。原理如图所示。 +![同步原理](figures/day3/sync_sample.png) + +计数信号量用于控制系统中共享资源的多个实例的使用,允许多个线程同时访问同一种资源的多个实例。计数信号量初始化为n(非负整数),n为共享资源的数目。计数信号量在线程申请并获得的时候减1,在释放时加1,值为0时不可获得。原理如图所示。 +![计数原理](figures/day3/count_sample.png) + +#### 信号量API +创建与删除信号量的API分别如下所示 +```c +rt_sem_t rt_sem_create(const char* name, + rt_uint32_t value, + rt_uint8_t flag); + +rt_err_t rt_sem_delete(rt_sem_t sem); +``` +创建信号量时,系统将先从对象管理器中分配一个semaphore对象,并初始化这个对象,然后初始化父类IPC对象以及与semaphore相关的部分。在创建信号量指定的参数中,信号量标志参数决定了当信号量不可用时,多个线程等待的排队方式。当选择RT_IPC_FLAG_FIFO(先进先出)方式时,那么等待线程队列将按照先进先出的方式排队,先进入的线程将先获得等待的信号量;当选择RT_IPC_FLAG_PRIO(优先级等待)方式时,等待线程队列将按照优先级进行排队,优先级高的等待线程将先获得等待的信号量。 + +删除信号量时,如果有现成正在等待该信号量,那么删除操作会先唤醒等待在该信号量上的线程(等待线程的返回值为 `-RT_ERROR` ),然后再释放信号量的内存资源。 + +信号量初始化与脱离,与create函数区别在于该函数静态创建信号量。脱离函数让静态创建的信号量对象从内核对象管理器中脱离。同样会唤醒等待的线程获得 `-RT_ERROR` 的返回值。 +```c +rt_err_t rt_sem_init(rt_sem_t sem, + const char *name, + rt_uint32_t value, + rt_uint8_t flag); + +rt_err_t rt_sem_detach(rt_sem_t sem); +``` + +获取信号量,用于获得信号量资源实例。信号量大于0时获得信号量,相应信号量值减1。信号量值等于0时,说明信号量资源实例不可用,申请的线程会根据time参数的情况选择直接返回,挂起等待一段时间或永久等待。若time时间内仍然得不到,线程将超时返回 `-RT_ETIMEOUT`。 +```c +rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time); + +rt_err_t rt_sem_trytake(rt_sem_t sem);//无等待获取信号量 +``` + +释放信号量,唤醒挂起在该信号量上的线程。若无等待,值加1。 +```c +rt_err_t rt_sem_release(rt_sem_t sem); +``` + +### 互斥量 +互斥量是一种特殊的二值信号量。它和信号量不同的是,它支持: +- 互斥量所有权:互斥量具有线程所有权,只有加锁的线程才能解锁,否则可能导致未定义行为(如死锁)。信号量则没有这个概念。 +- 递归访问 +- 防止优先级反转的特性。 + +> 优先级反转:当一个高优先级线程试图通过信号量机制访问共享资源时,如果该信号量已被一低优先级线程持有,而这个低优先级线程在运行过程中可能又被其它一些中等优先级的线程抢占,因此造成高优先级线程被许多具有较低优先级的线程阻塞,实时性难以得到保证。 + +互斥量解决优先级反转的原理为它实现了优先级继承协议。通过在一个高优先级线程A尝试获取共享资源而被挂起的期间,将低优先级线程C优先级提高到A的优先级别。 + +#### 互斥量API +创建与删除互斥量的API分别如下所示 +```c +rt_sem_t rt_mutex_create(const char* name, rt_uint8_t flag); + +rt_err_t rt_mutex_delete(rt_mutex_t mutex); +``` +创建互斥量时,它的名字由name所指定。当调用这个函数时,系统将先从对象管理器中分配一个mutex对象,并初始化这个对象,然后初始化父类IPC对象以及与mutex相关的部分。互斥量的fIag标志已经作废,无论用户选择RT_IPC_FLAG_PRIO还是RT_IPC_FLAG_FIFO,内核均按照RT_IPC_FLAG_PRIO处理。 + +删除互斥量时,所有等待此互斥量的线程都将被唤醒(等待线程的返回值为 `-RT_ERROR` ),然后系统将互斥量从内核对象管理器链表中删除并释放空间。 + +互斥量初始化与脱离,与create函数区别在于该函数静态创建互斥量。脱离函数让静态创建的互斥量对象从内核对象管理器中脱离。同样会唤醒等待的线程获得 `-RT_ERROR` 的返回值。 +```c +rt_err_t rt_mutex_init(rt_mutex_t mutex, + const char *name, + rt_uint8_t flag); + +rt_err_t rt_mutex_detach(rt_mutex_t mutex); +``` + +获取互斥量,现成拥有了对互斥量的所有权,即某一时刻一个互斥量只能被一个线程持有。如果互斥量已经被当前线程控制,则持有计数加1。如果被其他线程占有,当前线程在互斥量上挂起等待,直到其他线程释放或者等待超时。 +```c +rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time); + +rt_err_t rt_mutex_trytake(rt_mutex_t mutex);//无等待获取互斥量 +``` + +释放互斥量,完成互斥资源访问后应尽快释放占据的互斥量,使其他线程能即时获取。每释放一次持有计数减1,计数为0时变为可用,等待在该互斥量上的线程将被唤醒。若线程的优先级被提升,则恢复。 +```c +rt_err_t rt_sem_release(rt_sem_t sem); +``` + +### 事件集 +事件集是一个32bit的数,每个事件用一个bit位代表,触发方式有与触发、或触发。 +- 发送:可以从中断或者线程中进行发送 +- 接收:线程接收,条件检查(逻辑与方式、逻辑或方式) +![事件集示例](figures/day3/event_sample.png) + +#### 事件集API +创建与删除事件,创建时系统从对象管理器中分配事件集对象,并初始化,然后初始化父类IPC对象。系统不再使用创建的事件集对象时,通过删除事件集对象控制块释放系统资源。 +```c +rt_event_t rt_event_create(const char* name, rt_uint8_t flag); + +rt_err_t rt_event_delete(rt_event_t event); +``` +删除一个事件集对象时应确保该事件集不再被使用。删除前会唤醒所有挂起在该事件集上的线程(线程的返回值为 `-RT_ERROR`)然后释放事件集对象占用的内存块。 + +事件集初始化与脱离,与create函数区别在于该函数静态创建事件集,并加入系统对象容器中管理。脱离函数让静态创建的事件集对象从内核对象管理器中脱离。同样会唤醒等待的线程获得 `-RT_ERROR` 的返回值。 +```c +rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag); + +rt_err_t rt_event_detach(rt_event_t event); +``` + +发送事件,可以发送事件集的一个或多个事件。其中通过set是定事件集对象的时间标志值,然后遍历等待在event事件集对象上的等待线程链表,判断是否有线程的事件激活要求与当前event对象事件标志值匹配,若有则唤醒。 +```c +rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set); +``` + +接收事件,内核使用32位的无符号整数来标识事件集,每一位代表一个事件,因此一个事件集对象可同时等待接收32个事件,内核可以通过指定选择参数“逻辑与”或“逻辑或”来选择如何激活线程。 +```c +rt_err_t rt_event_recv(rt_event_t event, + rt_uint32_t set, + rt_uint8_t option, + rt_int32_t timeout, + rt_uint32_t* recved); +``` +系统首先根据set参数和接收选项option来判断它要接收的事件是否发生,如果已经发生,则根据参数option上是否设置有 `RT_EVENT_FLAG_CLEAR` 来决定是否重置事件的相应标志位,然后返回(其中recved参数返回接收到的事件);如果没有发生,则把等待的set和option参数填入线程本身的结构中,然后把线程挂起在此事件上,直到其等待的事件满足条件或等待时间超过指定的超时时间。如果超时时间设置为零,则表示当线程要接受的事件没有满足其要求时就不等待,而直接返回 `-RT_ETIMEOUT`。 + +## 线程间通信 +### 邮箱 +RT-Thread操作系统的邮箱用于线程间通信,特点是开销比较低,效率较高。邮箱中的每一封邮件只能容纳固定的4字节内容(针对32位处理系统,指针的大小即为4个字节,所以一封邮件恰好能够容纳一个指针)。如下图所示,线程或中断服务例程把一封4字节长度的邮件发送到邮箱中,而一个或多个线程可以从邮箱中接收这些邮件并进行处理。 +![邮箱](figures/day3/mainbox.png) + +邮件发送过程非阻塞,能够安全的应用于中断服务中,是线程、中断服务、定时器向线程发送消息的有效手段。通常来说,邮件收取过程可能是阻塞的,这取决于邮箱中是否有邮件,以及收取邮件时设置的超时时间。当邮箱中不存在邮件且超时时间不为0时,邮件收取过程将变成阻塞方 +式。在这类情况下,只能由线程进行邮件的收取。 + +当一个线程向邮箱发送邮件时,如果邮箱没满,将把邮件复制到邮箱中。如果邮箱已经满了,发送线程可以设置超时时间,选择等待挂起或直接返回 `-RT_EFULL`。如果发送线程选择挂起等待,那 +么当邮箱中的邮件被收取而空出空间来时,等待挂起的发送线程将被唤醒继续发送。当一个线程从邮箱中接收邮件时,如果邮箱是空的,接收线程可以选择是否等待挂起直到收到新的邮件而唤醒,或可以设置超时时间。当达到设置的超时时间,邮箱依然未收到邮件时,这个选择超时等待的线程将被唤醒并返回 `-RT_ETIMEOUT`。如果邮箱中存在邮件,那么接收线程将复制邮箱中的4个字节邮件到接收缓存中。 + +#### 邮箱API +邮箱的创建与删除 +```c +rt_mailbox_t rt_mb_create (const char* name, rt_size_t size, rt_uint8_t flag); + +rt_err_t rt_mb_delete(rt_mailbox_t mb); +``` +创建邮箱对象时会先从对象管理器中分配一个邮箱对象,然后给邮箱动态分配一块内存空间来存放邮件,这块内存的大小等于邮件大小(4字节)与邮箱容量的乘积,接着初始化接收邮件数目和发送邮件在邮箱中的偏移量。删除邮箱时,如果有线程被挂起在该邮箱对象上,内核先唤醒挂起在该邮箱上的所有线程(线程返回值是 `-RT_ERROR`),然后再释放邮箱使用的内存,最后删除邮箱对象。 + +邮箱的初始化与脱离 +```c +rt_err_t rt_mb_init(rt_mailbox_t mb, + const char* name, + void* msgpool, + rt_size_t size, + rt_uint8_t flag); + +rt_err_t rt_mb_detach(rt_mailbox_t mb); +``` +同样与create的区别为静态创建,以及把静态初始化的邮箱对象从内核对象管理器中脱离。 + +发送邮件 +```c +rt_err_t rt_mb_send(rt_mailbox_t mb, rt_uint32_t value); + +rt_err_t rt_mb_send_wait(rt_mailbox_t mb, + rt_uint32_t value, + rt_int32_t timeout);//有等待时间 + +rt_err_t rt_mb_urgent(rt_mailbox_t mb, rt_ubase_t value); +``` +线程或者中断服务程序可以通过邮箱给其他线程发送邮件。发送的邮件可以是32位任意格式的数据,一个整型值或者一个指向缓冲区的指针。当邮箱中的邮件已经满时,发送邮件的线程或者中断程序会收到 `-RT_EFULL` 的返回值。 + +对于wait函数,如果邮箱已经满了,那么发送线程将根据设定的timeout参数等待邮箱中因为收取邮件而空出空间。如果设置的超时时间到达依然没有空出空间,这时发送线程将被唤醒并返回错误码。 + +对于urgent函数,发送紧急邮件时,邮件被直接插队放入了邮件队首,这样,接收者就能够优先接收到紧急邮件,从而及时进行处理。 + +接收邮件 +```c +rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_uint32_t *value, rt_int32_t timeout); +``` +只有当接收者接收的邮箱中有邮件时,接收者才能立即取到邮件并返回RT_EOK的返回值,否则接收线程会根据超时时间设置,或挂起在邮箱的等待线程队列上,或直接返回。接收邮件时,接收者需指定接收邮件的邮箱句柄,并指定接收到的邮件存放位置以及最多能够等待的超时时间。如果接收时设定了超时,当指定的时间内依然未收到邮件时,将返回 `-RT_ETIMEOUT`。 +### 消息队列 +消息队列,也就是将多条消息排成的队列形式,是一种常用的线程间通信方式,可以应用在多种场合,线程间的消息交换,使用串口接收不定长数据等。线程可以将一条或多条消息放到消息队列中,同样一个或多个线程可以从消息队列中获得消息;同时消息队列提供异步处理机制可以起到缓冲消息的作用。 +![消息队列](figures/day3/msg_queue.png) + +使用消息队列实现线程间的异步通信工作,具有以下特性: +- 支持读消息超时机制 +- 支持等待方式发送消息 +- 允许不同长度(不超过队列节点最大值)任意类型消息 +- 支持发送紧急消息 +#### 消息队列API +创建消息队列时先从对象管理器中分配一个消息队列对象,然后给消息队列对象分配一块内存空间,组织成空闲消息链表,`这块内存的大小=[消息大小+消息头(用于链表连接的大小)]*消息队列最大个数`,接着再初始化消息队列;接口返回`RT_EOK`表示动态消息队列创建成功。 +```c +rt_mq_t rt_mq_create (const char*name,//消息队列名称 + rt_size_t msg_size,//消息队列中一条消息的最大长度,单位字节 + rt_size_t max_msgs,//消息队列的最大个数 + rt_uint8_t flag);//消息队列采用的等待方式 +``` +参数fIag可以取如下数值:RT_IPC_FLAG_FIFO(先进先出)或RT_IPC_FLAG_PRIO(优先级等待) + +消息发送 +```c +rt_err_t rt_mq_send (rt_mq_t mq,//消息队列对象的句柄 + void* buffer,//消息内容 + rt_size_t size);//消息大小 + +rt_err_t rt_mq_send_wait(rt_mq_t mq,//消息队列对象的句柄 + const void *buffer,//消息内容 + rt_size_t size,//消息大小 + rt_int32_t timeout);//超时时间 + +rt_err_t rt_mq_urgent (rt_mq_t mq,//消息队列对象的句柄 + void *buffer,//消息内容 + rt_size_t size);//消息大小 +``` +线程或者中断服务程序都可以给消息队列发送消息。当发送消息时,消息队列对象先从空闲消息链表上取下一个空闲消息块,把线程或者中断服务程序发送的消息内容复制到消息块上,然后把该消息块挂到消息队列的尾部。当且仅当空闲消息链表上有可用的空闲消息块时,发送者才能成功发送消息;当空闲消息链表上无可用消息块,说明消息队列已满,此时,发送消息的的线程或者中断程序会收到一个错误码(`-RT_EFULL`)。 + +对于wait函数,如果消息队列已经满了,那么发送线程将根据设定的timeout参数进行等待。如果设置的超时时间到达依然没有空出空间,这时发送线程将被唤醒并返回错误码。 + +对于ergent函数,当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂到队首,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。 + +接收消息 +```c +rt_err_t rt_mq_recv(rt_mq_t mq,//消息队列对象的句柄 + void* buffer,// 消息内容 + rt_size_t size,// 消息大小 + rt_int32_t timeout);//指定的超时时间 +``` +当消息队列中有消息时,接收者才能接收消息,否则接收者会根据超时时间设置,或挂起在消息队列的等待线程队列上,或直接返回。接收消息时,接收者需指定存储消息的消息队列对象句柄,并且指定一个内存缓冲区,接收到的消息内容将被复制到该缓冲区里。此外,还需指定未能及时取到消息时的超时时间,接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部。 + +### 信号 +信号(又称为软中断信号),在软件层次上是对中断机制的一种模拟,在原理上,一个线程收到一个信号与处理器收到一个中断请求可以说是类似的。 + +信号本质是软中断,用来通知线程发生了异步事件,用做线程之间的异常通知、应急处理。一个线程不必通过任何操作来等待信号的到达,事实上,线程也不知道信号到底什么时候到达,线程之间可以互相通过调用`rt_thread_kill()`发送软中断信号。 + +收到信号的线程对各种信号有不同的处理方法,处理方法可以分为三类: +- 第一种是类似中断的处理程序,对于需要处理的信号,线程可以指定处理函数,由该函数来处理。 +- 第二种方法是,忽略某个信号,对该信号不做任何处理,就像未发生过一样。 +- 第三种方法是,对该信号的处理保留系统的默认值。 + +假设线程1需要对信号进行处理,首先线程1安装一个信号并解除阻塞,并在安装的同时设定了对信号的异常处理方式;然后其他线程可以给线程1发送信号,触发线程1对该信号的处理。 +#### 信号API +安装 +```c +rt_sighandler_t rt_signal_install(int signo,rt_sighandler_t[] handler); +``` +如果线程要处理某一信号,那么就要在线程中安装该信号。安装信号主要用来确定信号值及线程针对该信号值的动作之间的映射关系,即线程将要处理哪个信号,该信号被传递给线程时,将执行何种操作。handler参数,决定了该信号的不同的处理方法。参数指向当信号发生时用户自定义的处理函数,由该函数来处理(类似中断的方式)。 +参数设为`SIG_IGN`,忽略某个信号,对该信号不做任何处理。参数设为`SIG_DFL`,系统会调用默认的处理函数`_signal_default_handler()`。 + +阻塞信号与解除信号阻塞 +```c +void rt_signal_mask(int signo); + +void rt_signal_unmask(int signo); +``` +信号阻塞,也可以理解为屏蔽信号。如果该信号被阻塞,则该信号将不会递达给安装此信号的线程,也不会引发软中断处理。线程中可以安装好几个信号,使用此函数可以对其中一些信号给予“关注”,那么发送这些信号都会引发该线程的软中断。 + +发送信号 +```c +int rt_thread_kill(rt_thread_t tid, int sig); +``` +当需要进行异常处理时,可以给设定了处理异常的线程发送信号。 + +等待信号 +```c +int rt_signal_wait(const rt_sigset_t *set, + rt_siginfo_t[] *si, rt_int32_t timeout); +``` +等待set信号的到来,如果没有等到这个信号,则将线程挂起,直到等到这个信号或者等待时间超过指定的超时时间timeout。如果等到了该信号,则将指向该信号体的指针存入si。 \ No newline at end of file