diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day1 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day1 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..08007a0d14f842cf84deedd4aac2f8f39c20c300 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day1 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" @@ -0,0 +1,56 @@ +# 【RSOC25】Day1 课程笔记:冯宾 + +## env的使用 + +安装git文件 + +获取RT-Thread 源码 +Git Bash里输入 `git clone https://gitee.com/rtthread/rt-thread.git` + +安装env 官网下载 + +添加qemu工具的环境变量,文件路径`D:\RTTread\env-windows\tools\qemu\qemu64` + +在`D:\RTTread\rt-thread\bsp\qemu-vexpress-a9 `下打开env工具输入 +`menuconfig` +`scons -j4`对文件进行编译 +`qemu-nographic.bat` + + +`pkgs --upgrade` 升级软件包 + +`pkgs --update` 更新软件包 + +## git的使用 + +注意:提交PR,需要将修改的代码提交到分支上,不要提交到主分支上 + +`git pull` 推送 + +`git add .` 添加修改的文件到暂存区 + +`git log` 查看日志 + +`git status` 查看文件状态 + +`git push origin first_notes_feng`用于将本地仓库中指定分支(first_notes_feng )的提交推送到远程仓库(origin ) + +`git switch master` 切换分支 + +`git checkout -b first_note_feng `创建一个名为 first_note_feng的分支 + +`git reset --hard HEAD~ `硬重置,是一个用于撤销提交的 Git 命令 + +`git reset --soft HEAD~` 软重置,把上一个提交的退回暂存区里,后面还可以重新提交 + +如果报错 `fatal: not a git repository (or any of the parent directories): .git` + +则需输入 +`cd .\rsoc-rtt\` +`ls` + +再次软重置 + +`git push origin first_notes_feng --force` 强制推送 + +在日志地方可以删除节点,删除后,需要更新 \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day2 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\344\273\243\347\240\201.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day2 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\344\273\243\347\240\201.md" new file mode 100644 index 0000000000000000000000000000000000000000..ae63112a717b2c55608d6d7fa4e5b7ea440d5886 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day2 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\344\273\243\347\240\201.md" @@ -0,0 +1,65 @@ +# 【RSOC25】Day2 课程代码:冯宾 +#include +#include +#include + +void usr_thread1(void) +{ +    while(1) +    { +        rt_kprintf("run in usr thread1\r\n"); +        rt_thread_mdelay(100); +    } +} + +void usr_thread2(void) +{ +    while(1) +    { +        rt_kprintf("run in usr thread2\r\n"); +        rt_thread_mdelay(100); +    } +} + +void usr_thread3(void) +{ +    while(1) +    { +        rt_kprintf("run in usr thread3\r\n"); +        rt_thread_mdelay(100); +    } +} +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_thread1 , RT_NULL , 1024 ,4 , 5); + +    if (tid1 != RT_NULL) +    { +        rt_thread_startup(tid1); +    } + +    tid2 = rt_thread_create("usr2" , usr_thread2 , RT_NULL , 1024 , 5 , 5); + +    if (tid2 != RT_NULL) +    { +        rt_thread_startup(tid2); +    } + +    tid3 = rt_thread_create("usr3" , usr_thread3 , RT_NULL , 1024 , 6 , 5); + +    if (tid3 != RT_NULL) +    { +        rt_thread_startup(tid3); +    } +    rt_kprintf("run in main thread\r\n"); + +    while(1) rt_thread_mdelay(1000); + +    return RT_EOK; +} + + diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day2 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day2 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..86861507eaff329479b15577fe4c04923e57ef59 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day2 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" @@ -0,0 +1,89 @@ +# 【RSOC25】Day2 课程笔记:冯宾 + +## rt_thread_init 和rt_thread_create 静态和动态线程区别 + +rt_thread_init   为静态线程,在编译阶段,代码编好后,为线程分配空间,这个空间,仅为这个线程使用。 + +适用于对安全有要求的场合 +几乎所有系统对系统内所有线程都是静态分配的方式 + +rt_thread_create  为动态线程   + +内存有限,但是需要的功能多,对安全没有太大的要求,为了内存富裕,采取动态分配。 + +动态内存运行一段时间过后,申请不到内存了,即为创建线程失败 + +## rt_thread_delete + +rt_thread_delete  删除一个已经创建的线程。该函数会终止指定线程的运行,并释放线程占用的系统资源(如线程控制块、堆栈空间等)。 + +## rt_thread_self + +rt_thread_self   用于获取当前正在执行的线程句柄(即线程控制块指针)。 + +## rt_thread_startup + +rt_thread_startup  通过该函数,可以将线程从初始状态转换到就绪状态,使其能够被操作系统调度执行。 + +## rt_thread_yield + +rt_thread_yield  用于主动让出 CPU 使用权,允许其他具有相同优先级的就绪线程获得执行机会。该函数在线程需要暂时放弃 CPU 资源时非常有用。 + +## rt_thread_find + +rt_thread_find   用于通过线程名称查找对应的线程句柄。这个函数在线程间通信或需要操作其他线程时非常有用。 +函数原型 + +## rt_thread_delay + +rt_thread_delay   是 RT-Thread 实时操作系统中用于使当前线程暂停执行(进入阻塞状态)的核心 API 函数。通过指定延时时间,线程可以主动释放 CPU 资源,让其他就绪线程有机会执行。、 + +## 时间线的单位是tick + +#define THREAD_TIMESLICE        5  //单位是毫秒 + +## 优先级大小:数字越小,优先级越大 + +#define THREAD_PRIORITY         25  //优先级是25 +#define RT_MAIN_THREAD_PRIORITY 10   //优先级是10 + +## 内核--线程接口参数 + +参数 + +name 线程的名称 +entry 线程的入口函数参数 +stack_size 线程栈的大小 +priority 线程的优先级 +tick 线程的时间片大小 + +返回 + +RE_EOK  线程创建成功 +-RE_ERROR  线程创建失败 + +## 线程状态切换 + +初始状态 +就绪状态 +关闭状态 +运行状态 +挂起状态:在一段时间内没有进行实际操作或任务处理 + +## 循环线程 + +无循环线程被执行完毕后,系统会自动回收资源,与需手动删除 + +循环线程需要有让出cpu的动作 +主动让出:使用系统延时 +被动让出:等待ipc + +## 系统的调度器 + +调度器的主要工作: +1.决定任务运行顺序 +2.执行任务切换 + +调度规则: +优先级抢占 +时间片轮转 diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/event_sample.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/event_sample.c" new file mode 100644 index 0000000000000000000000000000000000000000..46ac2be5cffa7521fe32c4b24cfbd2e236fd41b8 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/event_sample.c" @@ -0,0 +1,78 @@ +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +/* 事件控制块 */ +static rt_event_t event = RT_NULL; + +#define EVENT_FLAG3 (1 << 3) +#define EVENT_FLAG5 (1 << 5) + +/* 线程1入口 */ +static void thread1_entry(void *parameter) +{ + rt_uint32_t e; + + while (1) + { + /* 等待接收事件 */ + rt_event_recv(event, (EVENT_FLAG3 | EVENT_FLAG5), + RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, + RT_WAITING_FOREVER, &e); + + rt_kprintf("thread1: AND recv event 0x%x\n", e); + } +} + +/* 线程2入口 */ +static void thread2_entry(void *parameter) +{ + while (1) + { + rt_kprintf("thread2: send event 0x%x\n", EVENT_FLAG3); + /* 发送事件3 */ + rt_event_send(event, EVENT_FLAG3); + rt_thread_mdelay(200); + + rt_kprintf("thread2: send event 0x%x\n", EVENT_FLAG5); + /* 发送事件5 */ + rt_event_send(event, EVENT_FLAG5); + rt_thread_mdelay(200); + } +} + +static int event_sample(void) +{ + rt_thread_t tid; + + /* 创建一个事件集 */ + event = rt_event_create("event", RT_IPC_FLAG_FIFO); + if (event == RT_NULL) + { + rt_kprintf("create event failed.\n"); + return -1; + } + + /* 创建线程1 */ + tid = rt_thread_create("thread1", + thread1_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + /* 创建线程2 */ + tid = rt_thread_create("thread2", + thread2_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(event_sample, event sample); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/mailbox_sample.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/mailbox_sample.c" new file mode 100644 index 0000000000000000000000000000000000000000..8f4614fddc7a642c2f4d0a9a390889dad26b16da --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/mailbox_sample.c" @@ -0,0 +1,91 @@ +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 1024 +#define THREAD_TIMESLICE 5 + +/* 邮箱控制块 */ +static rt_mailbox_t mb = RT_NULL; + +/* 邮件池 */ +static char mb_pool[128]; + +/* 线程1入口 */ +static void thread1_entry(void *parameter) +{ + char buf = 'A'; + rt_err_t result; + + while (1) + { + /* 发送邮件 */ + result = rt_mb_send(mb, (rt_uint32_t)&buf); + if (result != RT_EOK) + { + rt_kprintf("rt_mb_send ERR\n"); + } + rt_kprintf("thread1: send a mail: %c\n", buf); + + /* 改变邮件内容 */ + buf++; + if (buf > 'Z') buf = 'A'; + + /* 线程休眠50ms */ + rt_thread_mdelay(50); + } +} + +/* 线程2入口 */ +static void thread2_entry(void *parameter) +{ + char *recv_mail; + rt_err_t result; + + while (1) + { + /* 等待邮件,超时时间500ms */ + result = rt_mb_recv(mb, (rt_uint32_t *)&recv_mail, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + rt_kprintf("thread2: recv a mail: %c\n", *recv_mail); + } + else + { + rt_kprintf("not recv mail\n"); + } + } +} + +static int mailbox_sample(void) +{ + rt_thread_t tid; + + /* 创建一个邮箱 */ + mb = rt_mb_create("mb", 3, RT_IPC_FLAG_FIFO); + if (mb == RT_NULL) + { + rt_kprintf("create mailbox failed.\n"); + return -1; + } + + /* 创建线程1 */ + tid = rt_thread_create("thread1", + thread1_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + /* 创建线程2 */ + tid = rt_thread_create("thread2", + thread2_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(mailbox_sample, mailbox sample); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/message_queue_sample.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/message_queue_sample.c" new file mode 100644 index 0000000000000000000000000000000000000000..0e190622e1e5b688352fd5618ed96cf1a3fffe65 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/message_queue_sample.c" @@ -0,0 +1,99 @@ +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +/* 消息队列控制块 */ +static rt_mq_t mq = RT_NULL; + +/* 消息队列中用到的放置消息的内存池 */ +static char msg_pool[2048]; + +/* 线程1入口 */ +static void thread1_entry(void *parameter) +{ + static char msg1[] = "message from thread1"; + static char msg2[] = "message from thread1"; + static int count = 0; + + while (1) + { + if (0 == (count % 2)) + { + /* 发送消息到消息队列中 */ + rt_mq_send(mq, msg1, sizeof(msg1)); + } + else + { + /* 发送消息到消息队列中 */ + rt_mq_send(mq, msg2, sizeof(msg2)); + } + count++; + + /* 线程休眠10ms */ + rt_thread_mdelay(10); + } +} + +/* 线程2入口 */ +static void thread2_entry(void *parameter) +{ + char buf[128]; + rt_err_t result; + rt_size_t size; + + while (1) + { + /* 从消息队列中接收消息 */ + result = rt_mq_recv(mq, buf, sizeof(buf), RT_WAITING_FOREVER); + if (result == RT_EOK) + { + rt_kprintf("thread2: recv msg from msg queue, size: %d\n", size); + } + else + { + rt_kprintf("receive message failed.\n"); + break; + } + } + /* 执行到这一步说明接收消息失败 */ + return; +} + +static int msgq_sample(void) +{ + rt_thread_t tid; + + /* 创建一个消息队列 */ + mq = rt_mq_create("mqt", /* 消息队列名字 */ + 128, /* 消息的最大长度 */ + 10, /* 消息队列的最大个数 */ + RT_IPC_FLAG_FIFO); /* 采用FIFO方式进行线程等待 */ + if (mq == RT_NULL) + { + rt_kprintf("create message queue failed.\n"); + return -1; + } + + /* 创建线程1 */ + tid = rt_thread_create("thread1", + thread1_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + /* 创建线程2 */ + tid = rt_thread_create("thread2", + thread2_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(msgq_sample, message queue sample); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/mutex_sample.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/mutex_sample.c" new file mode 100644 index 0000000000000000000000000000000000000000..0784daeac98ca740c8927966dcaf44be9de2fa33 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/mutex_sample.c" @@ -0,0 +1,99 @@ +#include + +#define THREAD_PRIORITY 10 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +/* 指向互斥量的指针 */ +static rt_mutex_t dynamic_mutex = RT_NULL; +static rt_thread_t tid1 = RT_NULL; +static rt_thread_t tid2 = RT_NULL; + +/* 线程1、2共用的全局变量 */ +static rt_uint32_t cnt = 0; + +/* 线程1入口 */ +static void thread1_entry(void *parameter) +{ + rt_err_t result; + + while (1) + { + /* 试图获取互斥量 */ + result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + rt_kprintf("thread1 take the mutex\n"); + + /* 对全局变量做自加操作 */ + cnt++; + rt_kprintf("thread1: cnt = %d\n", cnt); + + /* 释放互斥量 */ + rt_mutex_release(dynamic_mutex); + rt_kprintf("thread1 release the mutex\n"); + } + + /* 线程休眠100ms */ + rt_thread_mdelay(100); + } +} + +/* 线程2入口 */ +static void thread2_entry(void *parameter) +{ + rt_err_t result; + + while (1) + { + /* 试图获取互斥量 */ + result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + rt_kprintf("thread2 take the mutex\n"); + + /* 对全局变量做自减操作 */ + cnt--; + rt_kprintf("thread2: cnt = %d\n", cnt); + + /* 释放互斥量 */ + rt_mutex_release(dynamic_mutex); + rt_kprintf("thread2 release the mutex\n"); + } + + /* 线程休眠150ms */ + rt_thread_mdelay(150); + } +} + +static int mutex_sample(void) +{ + /* 创建一个动态互斥量 */ + dynamic_mutex = rt_mutex_create("dmutex", RT_IPC_FLAG_FIFO); + if (dynamic_mutex == RT_NULL) + { + rt_kprintf("create dynamic mutex failed.\n"); + return -1; + } + + /* 创建线程1 */ + tid1 = rt_thread_create("t1", + thread1_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + /* 创建线程2 */ + tid2 = rt_thread_create("t2", + thread2_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (tid2 != RT_NULL) + rt_thread_startup(tid2); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(mutex_sample, mutex sample); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/semaphore_sample.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/semaphore_sample.c" new file mode 100644 index 0000000000000000000000000000000000000000..c3c546e623bcf3a0ae949122ae7a95bc8be904bc --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/semaphore_sample.c" @@ -0,0 +1,92 @@ +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +/* 指向信号量的指针 */ +static rt_sem_t dynamic_sem = RT_NULL; + +/* 线程1入口 */ +static void thread1_entry(void *parameter) +{ + rt_err_t result; + rt_uint32_t count = 0; + + while (1) + { + if (count <= 100) + { + count++; + rt_kprintf("thread1 release a dynamic semaphore.\n"); + /* 释放一个信号量 */ + rt_sem_release(dynamic_sem); + } + else + return; + + /* 线程休眠100ms */ + rt_thread_mdelay(100); + } +} + +/* 线程2入口 */ +static void thread2_entry(void *parameter) +{ + rt_err_t result; + rt_uint32_t count = 0; + + while (1) + { + /* 永久等待信号量 */ + result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + count++; + rt_kprintf("thread2 take a dynamic semaphore. count = %d\n", count); + } + else + { + rt_kprintf("thread2 take semaphore failed\n"); + return; + } + } +} + +static int semaphore_sample(void) +{ + rt_thread_t tid; + + /* 创建一个动态信号量,初始值为0 */ + dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO); + if (dynamic_sem == RT_NULL) + { + rt_kprintf("create dynamic semaphore failed.\n"); + return -1; + } + else + { + rt_kprintf("create done. dynamic semaphore value = 0.\n"); + } + + /* 创建线程1 */ + tid = rt_thread_create("thread1", + thread1_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + /* 创建线程2 */ + tid = rt_thread_create("thread2", + thread2_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY + 1, THREAD_TIMESLICE); + if (tid != RT_NULL) + rt_thread_startup(tid); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(semaphore_sample, semaphore sample); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/signal_sample.c" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/signal_sample.c" new file mode 100644 index 0000000000000000000000000000000000000000..e9607d7731f3fb8fadcfbf129d1222870a159be7 --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/signal_sample.c" @@ -0,0 +1,102 @@ +#include + +#define THREAD_PRIORITY 20 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +/* 线程控制块指针 */ +static rt_thread_t tid1 = RT_NULL; +static rt_thread_t tid2 = RT_NULL; + +/* 信号值 */ +#define SIG_USR1 0x01 +#define SIG_USR2 0x02 + +/* 信号处理函数 */ +static void signal_handler(int sig) +{ + switch (sig) + { + case SIG_USR1: + rt_kprintf("thread1 received signal: SIG_USR1\n"); + break; + case SIG_USR2: + rt_kprintf("thread1 received signal: SIG_USR2\n"); + break; + default: + rt_kprintf("thread1 received an unknown signal: %d\n", sig); + break; + } +} + +/* 线程1入口函数 */ +static void thread1_entry(void *parameter) +{ + /* 设置信号处理函数 */ + signal(SIG_USR1, signal_handler); + signal(SIG_USR2, signal_handler); + + while (1) + { + rt_kprintf("thread1 is running...\n"); + rt_thread_mdelay(2000); + } +} + +/* 线程2入口函数 */ +static void thread2_entry(void *parameter) +{ + rt_uint8_t count = 0; + + while (1) + { + count++; + if (count % 2 == 0) + { + /* 发送SIG_USR1信号给线程1 */ + rt_kprintf("thread2 send SIG_USR1 to thread1\n"); + kill(tid1, SIG_USR1); + } + else + { + /* 发送SIG_USR2信号给线程1 */ + rt_kprintf("thread2 send SIG_USR2 to thread1\n"); + kill(tid1, SIG_USR2); + } + + rt_thread_mdelay(1000); + } +} + +/* 信号示例程序 */ +int signal_sample(void) +{ + /* 创建线程1 */ + tid1 = rt_thread_create("t1", + thread1_entry, + RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, + THREAD_TIMESLICE); + if (tid1 != RT_NULL) + { + rt_thread_startup(tid1); + } + + /* 创建线程2 */ + tid2 = rt_thread_create("t2", + thread2_entry, + RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY + 1, + THREAD_TIMESLICE); + if (tid2 != RT_NULL) + { + rt_thread_startup(tid2); + } + + return 0; +} + +/* 导出到msh命令列表中 */ +MSH_CMD_EXPORT(signal_sample, signal sample); \ No newline at end of file diff --git "a/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..552fc0fbefe7812e0b4783b5a8520899e750293b --- /dev/null +++ "b/2025/\347\254\2546\347\273\204(GD32F527I-EVAL)/\343\200\220RSOC25\343\200\221Day3 \350\257\276\347\250\213\347\254\224\350\256\260\357\274\232\345\206\257\345\256\276/\347\254\224\350\256\260.md" @@ -0,0 +1,107 @@ +# 【RSOC25】Day3 课程笔记:冯宾 + +` flag ` 在创建信号量指定的参数中,信号量标志参数决定了当信号量不可用时,多个线程等待的`排队方式`。当选择`RT_IPCFLAGFIFO(先进先出)`方式时,那么等待线程队列将按照先进先出的方式排队,先进入的线程将先获得等待的信号量;当选择 `RTIPCFLAG PRI0(优先级等待)`方式时,等待线程队列将按照优先级进行排队,优先级高的等待线程将先获得等待的信号量。 + +`rt err_t rt_sem_detach(rt_sem_t sem)` 脱离信号量就是让信号量对象从内核对象管理器中`脱离`,适用于静态初始化的信号量。 + +使用该函数后,内核先唤醒所有挂在该信号量等待队列上的线程,然后将该信号量从内核对象管理器中脱离。原来挂起在信号量上的等待线程将获得`-RTERROR `的返回值。 + +`rt_err_t rt_sem_take(rt_sem_t sem,rt_int32_t time)`, +线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号量,并且相应的信号量值会`减 1`。 +在调用这个函数时,如果信号量的值等于零,那么说明当前信号量资源实例不可用,申请该信号量的线程将根据 time 参数的情况选择`直接返回、或挂起等待一段时间、或永久等待`,直到其他线程或中断释放该信号量。如果在参数 time 指定的时间内依然得不到信号量,线程将超时返回,返回值是-RT ETIMEOUT + +`rt_err_t rt_sem_trytake(rt_sem_t sem)`; +当用户不想在申请的信号量上挂起线程进行等待时,可以使用无等待方式获取信号量。 + +`rt_err_t rt_sem_release(rt_sem_t sem)` +释放信号量可以唤醒挂起在该信号量上的线程 + +`rt_err_t rt_mutex_release(rt_mutex_t mutex)` +, +当线程完成互斥资源的访问后,应`尽快释放`它占据的互斥量,使得其他线程能及时获取该互斥量。 + +使用该函数接口时,只有已经拥有互斥量控制权的线程才能释放它,`每释放一次该互斥量,它的持有计数就减 1。当该互斥量的持有计数为零时(即持有线程已经释放所有的持有操作)`,它变为可用等待在该互斥量上的线程将被唤醒。如果线程的运行优先级被互斥量提升,那么当互斥量被释放后线程恢复为持有互斥量前的优先级。 + +## 互斥量 + +`互斥量`又叫相互排斥的信号量,是一种特殊的二值信号量。它和信号量不同的是,它支持: + +1.互斥量所有权:互斥量具有线程所有权,只有加锁的线程才能解锁,否则可能导致未定义行为(如1.死锁) +2.递归访问: +3.防止优先级反转的特性, + +## 优先级反转(Prioritylnversion): + +所谓优先级翻转,即当一个高优先级线程试图通过信号量机制访问共享资源时,如果该信号量已被一低优先级线程持有,而这个低优先级线程在运行过程中可能又被其它一些中等优先级的线程抢占,因此造成高优先级线程被许多具有较低优先级的线程阻塞,实时性难以得到保证。 + +## 事件集 + +事件集是一个32bit 的数 每个事件用一个bit位代表 + +触发方式有 与触发 或触发 + +## 消息邮箱 + +RT-Thread 操作系统的邮箱用于线程间通信,特点是 `开销比较低,效率较高 `。邮箱中的每一封邮件只能容纳固定的 4 字节内容(针对 32 位处理系统,指针的大小即为4个字节,所以一封邮件恰好能够容纳一个指针)。典型的邮箱也称作 `交换消息`, + +`非阻塞方式`的邮件发送过程能够安全的应用于中断服务中,是`线程、中断服务、定时器向线程`发送消息的有效手段。 + +`删除邮箱` +rt_err_t rt_mb_delete(rt_mailbox_t mb); +当用 rt_mb create()创建的邮箱不再被使用时,应该删除它来释放相应的系统资源,一旦操作完成,邮箱将被永久性的删除。 + +`发送邮件` + +rt_err_t rt_mb_send(rt_mailbox_t mb, rt_uint32_t value);线程或者中断服务程序可以通过邮箱给其他线程发送邮件。 + +发送的邮件可以是 32 位任意格式的数据,一个整型值或者一个指向缓冲区的指针。当邮箱中的邮件已经满时,发送邮件的线程或者中断程序会收到-RTEFULL 的返回值。 + +`等待方式发送邮件` + +rt_err_t rt_mb_send_wait(rt_mailbox_t mb, +rt_uint32_t value, +rt int32_t timeout); + +rt mb send wait()与 rt mb send()的区别在于有`等待时间`,如果邮箱已经满了,那么发送线程将根据设定的 timeout 参数等待邮箱中因为收取邮件而空出空间。如果设置的超时时间到达依然没有空出空间,这时发送线程将被唤醒并返回错误码。 + +`接受邮件` + +rt_err_t rt_mb_recv (rt_mailbox_t mb, rt _uint32_t* value, rt_int32_t timeout); + +只有当接收者接收的邮箱中有邮件时,接收者才能立即取到邮件并返回 RTEOK 的返回值,否则接收线程会根据超时时间设置,或挂起在邮箱的等待线程队列上,或直接返回。 + +## 消息队列 + +消息队列,也就是将多条消息排成的队列形式,是一种常用的`线程间通信方式`,可以应用在多种场合,线程间的消息交换,使用串口接收不定长数据等。线程可以将一条或多条消息放到消息队列中,同样一个或多个线程可以从消息队列中获得消息;同时消息队列提供`异步处理机制`可以起到缓冲消息的作用. + +使用消息队列实现线程间的`异步通信工作`,具有以下`特性`: + 支持读消息超时机制 + 支持等待方式发送消息 + 允许不同长度(不超过队列节点最大值)任意类型消息 + 支持发送紧急消息 + +线程先得到的是先进入消息队列的消息,即`先进先出` + +创建消息队列时先从对象管理器中分配一个消息队列对象,然后给消息队列对象分配一块内存空间,组织成空闲消息链表,`这块内存的大小` =[消息大小 + 消息头(用于链表连接)的大小]*`消息队列最大个数`,接着再初始化消息队列;接口返回RTEOK表示动态消息队列创建成功。 + +`消息队列句柄 ` +rt ert mg tmg=RT NULL: + +`创建消息队列对象,返回消息队列句柄` +mg=rt mg_create("mg",4,10,RT IPC FLAG FIFO); //名称,消息长度,消息个数,等待方式 + +## 信号(又称为软中断信号) + +在软件层次上是对中断机制的一种模拟,在原理上,一个线程收到一个信号与处理器收到一个中断请求可以说是类似的。 + +信号在 RT-Thread 中用作异步通信,POSIX 标准定义了 sigset t 类型来定义一个信号集,然而sigset_t 类型在不同的系统可能有不同的定义方式,在 RT-Thread 中,将 sigset_t 定义成了unsigned long型,并命名为rt_sigset t,应用程序能够使用的信号为 SIGUSR1(10)和SIGUSR2(12)。 + +信号本质是软中断,用来通知线程发生了异步事件,用做线程之间的异常通知、应急处理。一个线程不必通过任何操作来等待信号的到达,事实上,线程也不知道信号到底什么时候到达,线程之间可以互相通过调用rtthread kill()发送软中断信号 + +`API:接收消息` + +当消息队列中有消息时,接收者才能接收消息,否则接收者会根据超时时间设置,或挂起在消息队列的等待线程队列上,或直接返回。接收消息函数接口如下 +//消息队列对象的句柄rt_err_trt_mg recv(rt_mg_t mg, +void* buffer,// 消息内容 +// 消息大小rt size_t_size, +rt_int32_ttimeout);//指定的超时时间 \ No newline at end of file