From ea7b3847f403401a50078a359fcf705897655f27 Mon Sep 17 00:00:00 2001 From: james <1943357252@qq.com> Date: Tue, 23 Jul 2024 17:15:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86=E6=96=B0=E5=BB=BADay,?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {hello => Day1}/SConscript | 0 {hello => Day1}/hello.c | 0 {hello => Day1}/hello.h | 0 Day1/mailbox_sample.c | 117 +++++++++++++++++++++++++++++++ Day1/msgq_sample.c | 140 +++++++++++++++++++++++++++++++++++++ Day1/mutex_sample.c | 94 +++++++++++++++++++++++++ Day1/semaphore_sample.c | 102 +++++++++++++++++++++++++++ Day1/thread_sample.c | 75 ++++++++++++++++++++ applications/main.c | 114 +++++++++++++++++++++++++----- 9 files changed, 623 insertions(+), 19 deletions(-) rename {hello => Day1}/SConscript (100%) rename {hello => Day1}/hello.c (100%) rename {hello => Day1}/hello.h (100%) create mode 100644 Day1/mailbox_sample.c create mode 100644 Day1/msgq_sample.c create mode 100644 Day1/mutex_sample.c create mode 100644 Day1/semaphore_sample.c create mode 100644 Day1/thread_sample.c diff --git a/hello/SConscript b/Day1/SConscript similarity index 100% rename from hello/SConscript rename to Day1/SConscript diff --git a/hello/hello.c b/Day1/hello.c similarity index 100% rename from hello/hello.c rename to Day1/hello.c diff --git a/hello/hello.h b/Day1/hello.h similarity index 100% rename from hello/hello.h rename to Day1/hello.h diff --git a/Day1/mailbox_sample.c b/Day1/mailbox_sample.c new file mode 100644 index 0000000..1232eef --- /dev/null +++ b/Day1/mailbox_sample.c @@ -0,0 +1,117 @@ +/* + * 程序清单:邮箱例程 + * + * 这个程序会创建2个动态线程,一个静态的邮箱对象,其中一个线程往邮箱中发送邮件, + * 一个线程往邮箱中收取邮件。 + */ +#include + +#define THREAD_PRIORITY 10 +#define THREAD_TIMESLICE 5 + +/* 邮箱控制块 */ +static struct rt_mailbox mb; +/* 用于放邮件的内存池 */ +static char mb_pool[128]; +static char mb_str1[] = "I'm a mail!"; +static char mb_str2[] = "this is another mail!"; +static char mb_str3[] = "over"; + +static char thread1_stack[1024]; +static struct rt_thread thread1; + +/* 线程1入口 */ +static void thread1_entry(void *parameter) +{ + char *str; + + while (1) + { + rt_kprintf("thread1: try to recv a mail\n"); + + /* 从邮箱中收取邮件 */ + if (rt_mb_recv(&mb, (rt_ubase_t *)&str, RT_WAITING_FOREVER) == RT_EOK) + { + rt_kprintf("thread1: get a mail from mailbox, the content:%s\n", str); + if (str == mb_str3) + break; + + /* 延时100ms */ + rt_thread_mdelay(100); + } + } + /* 执行邮箱对象脱离 */ + rt_mb_detach(&mb); +} + +static char thread2_stack[1024]; +static struct rt_thread thread2; + +/* 线程2入口 */ +static void thread2_entry(void *parameter) +{ + rt_uint8_t count; + + count = 0; // 初始化计数器为0 + while (count < 10) // 循环10次 + { + count ++; // 计数器递增 + if (count & 0x1) // 判断计数器是否为奇数 + { + /* 发送mb_str1地址到邮箱中 */ + rt_mb_send(&mb, (rt_uint32_t)&mb_str1); + } + else // 否则,即计数器为偶数 + { + /* 发送mb_str2地址到邮箱中 */ + rt_mb_send(&mb, (rt_uint32_t)&mb_str2); + } + + /* 延时200ms */ + rt_thread_mdelay(200); + } + + /* 发送邮件告诉线程1,线程2已经运行结束 */ + rt_mb_send(&mb, (rt_uint32_t)&mb_str3); +} + +int mailbox_sample(void) +{ + rt_err_t result; + + /* 初始化一个mailbox */ + result = rt_mb_init(&mb, + "mbt", /* 名称是mbt */ + &mb_pool[0], /* 邮箱用到的内存池是mb_pool */ + sizeof(mb_pool) / sizeof(rt_ubase_t), /* 邮箱中的邮件数目,sizeof(rt_ubase_t)表示指针大小 */ + RT_IPC_FLAG_PRIO); /* 采用PRIO方式进行线程等待 */ + if (result != RT_EOK) + { + rt_kprintf("init mailbox failed.\n"); + return -1; + } + + rt_thread_init(&thread1, + "thread1", + thread1_entry, + RT_NULL, + &thread1_stack[0], + sizeof(thread1_stack), + THREAD_PRIORITY, THREAD_TIMESLICE); + + rt_thread_startup(&thread1); + + rt_thread_init(&thread2, + "thread2", + thread2_entry, + RT_NULL, + &thread2_stack[0], + sizeof(thread2_stack), + THREAD_PRIORITY, THREAD_TIMESLICE); + + rt_thread_startup(&thread2); + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(mailbox_sample, mailbox sample); diff --git a/Day1/msgq_sample.c b/Day1/msgq_sample.c new file mode 100644 index 0000000..f1fa609 --- /dev/null +++ b/Day1/msgq_sample.c @@ -0,0 +1,140 @@ +/* + * 程序清单:消息队列例程 + * + * 这个程序会创建2个动态线程,一个线程会从消息队列中收取消息;一个线程会定时给消 + * 息队列发送 普通消息和紧急消息。 + */ +#include + +#define THREAD_PRIORITY 25 +#define THREAD_TIMESLICE 5 + +/* 消息队列控制块 */ +static struct rt_messagequeue mq; +/* 消息队列中用到的放置消息的内存池 */ +static rt_uint8_t msg_pool[2048]; + +static char thread1_stack[1024]; +static struct rt_thread thread1; + +/* 线程1入口函数 */ +static void thread1_entry(void *parameter) +{ + char buf = 0; // 用于接收消息的缓冲区 + rt_uint8_t cnt = 0; // 消息计数器 + + while (1) + { + /* 从消息队列中接收消息 */ + if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) > 0) + { + rt_kprintf("thread1: recv msg from msg queue, the content: %c\n", buf); + if (cnt == 19) + { + break; // 接收20次消息后退出 + } + } + /* 延时50ms */ + cnt++; + rt_thread_mdelay(50); + } + rt_kprintf("thread1: detach mq \n"); + rt_mq_detach(&mq); // 脱离消息队列 +} + +static char thread2_stack[1024]; +static struct rt_thread thread2; + +/* 线程2入口 */ +static void thread2_entry(void *parameter) +{ + int result; + char buf = 'A'; // 要发送的消息内容 + rt_uint8_t cnt = 0; // 消息计数器 + + while (1) + { + if (cnt == 8) + { + /* 发送紧急消息到消息队列中 */ + result = rt_mq_urgent(&mq, &buf, 1); + if (result != RT_EOK) + { + rt_kprintf("rt_mq_urgent ERR\n"); + } + else + { + rt_kprintf("thread2: send urgent message - %c\n", buf); + } + } + else if (cnt >= 20) /* 发送20次消息之后退出 */ + { + rt_kprintf("message queue stop send, thread2 quit\n"); + break; + } + else + { + /* 发送消息到消息队列中 */ + result = rt_mq_send(&mq, &buf, 1); + if (result != RT_EOK) + { + rt_kprintf("rt_mq_send ERR\n"); + } + + rt_kprintf("thread2: send message - %c\n", buf); + } + buf++; + cnt++; + /* 延时5ms */ + rt_thread_mdelay(5); + } +} + +/* 消息队列示例的初始化 */ +int msgq_sample(void) +{ + rt_err_t result; + + /* 初始化消息队列 */ + result = rt_mq_init(&mq, + "mqt", /* 名称是mqt */ + &msg_pool[0], /* 内存池指向msg_pool */ + 1, /* 每个消息的大小是1字节 */ + sizeof(msg_pool), /* 内存池的大小是msg_pool的大小 */ + RT_IPC_FLAG_PRIO); /* 如果有多个线程等待,按照优先级的方式分配消息 */ + + if (result != RT_EOK) + { + rt_kprintf("init message queue failed.\n"); + return -1; + } + + /* 初始化线程1 */ + rt_thread_init(&thread1, + "thread1", /* 线程名称 */ + thread1_entry, /* 线程入口函数 */ + RT_NULL, /* 入口函数参数 */ + &thread1_stack[0], /* 线程栈起始地址 */ + sizeof(thread1_stack), /* 线程栈大小 */ + THREAD_PRIORITY, THREAD_TIMESLICE); /* 线程优先级和时间片大小 */ + + /* 启动线程1 */ + rt_thread_startup(&thread1); + + /* 初始化线程2 */ + rt_thread_init(&thread2, + "thread2", /* 线程名称 */ + thread2_entry, /* 线程入口函数 */ + RT_NULL, /* 入口函数参数 */ + &thread2_stack[0], /* 线程栈起始地址 */ + sizeof(thread2_stack), /* 线程栈大小 */ + THREAD_PRIORITY-1, THREAD_TIMESLICE); /* 线程优先级和时间片大小 */ + + /* 启动线程2 */ + rt_thread_startup(&thread2); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(msgq_sample, msgq sample); \ No newline at end of file diff --git a/Day1/mutex_sample.c b/Day1/mutex_sample.c new file mode 100644 index 0000000..8aee3ce --- /dev/null +++ b/Day1/mutex_sample.c @@ -0,0 +1,94 @@ +/* + * 程序清单:互斥锁例程 + * + * 互斥锁是一种保护共享资源的方法。当一个线程拥有互斥锁的时候, + * 可以保护共享资源不被其他线程破坏。线程1对2个number分别进行加1操作 + * 线程2也会对2个number分别进行加1操作。使用互斥量保证2个number值保持一致 + */ +#include + +#define THREAD_PRIORITY 8 +#define THREAD_TIMESLICE 5 + +/* 指向互斥量的指针 */ +static rt_mutex_t dynamic_mutex = RT_NULL; +static rt_uint8_t number1, number2 = 0; + + +static char thread1_stack[1024]; +static struct rt_thread thread1; +static void rt_thread_entry1(void *parameter) +{ + while (1) + { + /* 线程1获取到互斥量后,先后对number1、number2进行加1操作,然后释放互斥量 */ + rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER); + number1++; + rt_thread_mdelay(10); + number2++; + rt_mutex_release(dynamic_mutex); + } +} + + +static char thread2_stack[1024]; +static struct rt_thread thread2; +static void rt_thread_entry2(void *parameter) +{ + while (1) + { + /* 线程2获取到互斥量后,检查number1、number2的值是否相同,相同则表示mutex起到了锁的作用 */ + rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER); + if (number1 != number2) + { + rt_kprintf("not protect.number1 = %d, mumber2 = %d \n", number1, number2); + } + else + { + rt_kprintf("mutex protect ,number1 = mumber2 is %d\n", number1); + } + + number1++; + number2++; + rt_mutex_release(dynamic_mutex); + + if (number1 >= 50) + return; + } +} + +/* 互斥量示例的初始化 */ +int mutex_sample(void) +{ + /* 创建一个动态互斥量 */ + dynamic_mutex = rt_mutex_create("dmutex", RT_IPC_FLAG_PRIO); + if (dynamic_mutex == RT_NULL) + { + rt_kprintf("create dynamic mutex failed.\n"); + return -1; + } + + rt_thread_init(&thread1, + "thread1", + rt_thread_entry1, + RT_NULL, + &thread1_stack[0], + sizeof(thread1_stack), + THREAD_PRIORITY, THREAD_TIMESLICE); + + rt_thread_startup(&thread1); + + rt_thread_init(&thread2, + "thread2", + rt_thread_entry2, + RT_NULL, + &thread2_stack[0], + sizeof(thread2_stack), + THREAD_PRIORITY - 1, THREAD_TIMESLICE); + + rt_thread_startup(&thread2); + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(mutex_sample, mutex sample); diff --git a/Day1/semaphore_sample.c b/Day1/semaphore_sample.c new file mode 100644 index 0000000..fa2f3f7 --- /dev/null +++ b/Day1/semaphore_sample.c @@ -0,0 +1,102 @@ +#include + +#define THREAD_PRIORITY 25 +#define THREAD_TIMESLICE 5 + +/* 指向信号量的指针 */ +static rt_sem_t dynamic_sem = RT_NULL; + +static char thread1_stack[1024]; +static struct rt_thread thread1; + +/* 线程1入口函数 */ +static void rt_thread1_entry(void *parameter) +{ + static rt_uint8_t count = 0; + + while(1) + { + if(count <= 100) + { + count++; // 计数器递增 + } + else + { + return; // 计数器大于100时退出线程 + } + + /* count 每计数 10 次,就释放一次信号量 */ + if(0 == (count % 10)) + { + rt_kprintf("t1 release a dynamic semaphore.\n"); + rt_sem_release(dynamic_sem); // 释放信号量 + } + } +} + +static char thread2_stack[1024]; +static struct rt_thread thread2; + +/* 线程2入口函数 */ +static void rt_thread2_entry(void *parameter) +{ + static rt_err_t result; + static rt_uint8_t number = 0; + + while(1) + { + /* 永久方式等待信号量,获取到信号量,则执行 number 自加的操作 */ + result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_kprintf("t2 take a dynamic semaphore, failed.\n"); + rt_sem_delete(dynamic_sem); // 删除信号量 + return; + } + else + { + number++; // 信号量获取成功,number 自加 + rt_kprintf("t2 take a dynamic semaphore. number = %d\n", number); + } + } +} + +/* 信号量示例的初始化 */ +int semaphore_sample(void) +{ + /* 创建一个动态信号量,初始值是 0 */ + dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_PRIO); + 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 */ + rt_thread_init(&thread1, + "thread1", /* 线程名称 */ + rt_thread1_entry, /* 线程入口函数 */ + RT_NULL, /* 入口函数参数 */ + &thread1_stack[0], /* 线程栈起始地址 */ + sizeof(thread1_stack), /* 线程栈大小 */ + THREAD_PRIORITY, THREAD_TIMESLICE); /* 线程优先级和时间片大小 */ + rt_thread_startup(&thread1); + + /* 初始化并启动线程2 */ + rt_thread_init(&thread2, + "thread2", /* 线程名称 */ + rt_thread2_entry, /* 线程入口函数 */ + RT_NULL, /* 入口函数参数 */ + &thread2_stack[0], /* 线程栈起始地址 */ + sizeof(thread2_stack), /* 线程栈大小 */ + THREAD_PRIORITY-1, THREAD_TIMESLICE); /* 线程优先级和时间片大小 */ + rt_thread_startup(&thread2); + + return 0; +} +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(semaphore_sample, semaphore sample); \ No newline at end of file diff --git a/Day1/thread_sample.c b/Day1/thread_sample.c new file mode 100644 index 0000000..d6fb561 --- /dev/null +++ b/Day1/thread_sample.c @@ -0,0 +1,75 @@ +/* + * 程序清单:创建、初始化/脱离线程 + * + * 这个例子会创建两个线程,一个动态线程,一个静态线程。 + * 静态线程在运行完毕后自动被系统脱离,动态线程一直打印计数。 + */ +#include + +#define THREAD_PRIORITY 25 +#define THREAD_STACK_SIZE 512 +#define THREAD_TIMESLICE 5 + +static rt_thread_t tid1 = RT_NULL; + +/* 线程1的入口函数 */ +static void thread1_entry(void *parameter) +{ + rt_uint32_t count = 0; + + while (1) + { + /* 线程1采用低优先级运行,一直打印计数值 */ + rt_kprintf("thread1 count: %d\n", count++); + rt_thread_mdelay(500); // 延时500毫秒 + } +} + +static char thread2_stack[1024]; +static struct rt_thread thread2; + +/* 线程2入口 */ +static void thread2_entry(void *param) +{ + rt_uint32_t count = 0; + + /* 线程2拥有较高的优先级,以抢占线程1而获得执行 */ + for (count = 0; count < 10 ; count++) + { + /* 线程2打印计数值 */ + rt_kprintf("thread2 count: %d\n", count); + } + rt_kprintf("thread2 exit\n"); + + /* 线程2运行结束后也将自动被系统脱离 */ +} + +/* 线程示例 */ +int thread_sample(void) +{ + /* 创建线程1,名称是thread1,入口是thread1_entry */ + tid1 = rt_thread_create("thread1", + thread1_entry, RT_NULL, + THREAD_STACK_SIZE, + THREAD_PRIORITY, THREAD_TIMESLICE); + /* 如果获得线程控制块,启动这个线程 */ + if (tid1 != RT_NULL) + rt_thread_startup(tid1); + + /* 初始化线程2,名称是thread2,入口是thread2_entry */ + rt_thread_init(&thread2, + "thread2", + thread2_entry, + RT_NULL, + &thread2_stack[0], + sizeof(thread2_stack), + THREAD_PRIORITY - 1, THREAD_TIMESLICE); + + /* 启动线程2 */ + rt_thread_startup(&thread2); + + return 0; +} + +/* 导出到 msh 命令列表中 */ +MSH_CMD_EXPORT(thread_sample, thread sample); \ No newline at end of file diff --git a/applications/main.c b/applications/main.c index 33ea58f..4704b95 100644 --- a/applications/main.c +++ b/applications/main.c @@ -16,31 +16,107 @@ #include #endif /* RT_USING_NANO */ -// #define GPIO_LED_B GET_PIN(F, 11) -// #define GPIO_LED_R GET_PIN(F, 12) -// int main(void) +#define GPIO_LED_B GET_PIN(F, 11) +#define GPIO_LED_R GET_PIN(F, 12) +int main(void) +{ + rt_pin_mode(GPIO_LED_R, PIN_MODE_OUTPUT); + + while (1) + { + rt_pin_write(GPIO_LED_R, PIN_HIGH); + rt_thread_mdelay(500); + rt_pin_write(GPIO_LED_R, PIN_LOW); + rt_thread_mdelay(500); + } +} + +// #include +// #include "hello.h" + +// int main(void) // { -// rt_pin_mode(GPIO_LED_R, PIN_MODE_OUTPUT); +// while(1) +// { +// Print_Hello_World(); +// rt_thread_mdelay(500); +// } + +// return 0; +// } + +/* + * 程序清单:创建、初始化/脱离线程 + * + * 这个例子会创建两个线程,一个动态线程,一个静态线程。 + * 静态线程在运行完毕后自动被系统脱离,动态线程一直打印计数。 + */ +// #include + +// #define THREAD_PRIORITY 25 +// #define THREAD_STACK_SIZE 512 +// #define THREAD_TIMESLICE 5 + +// static rt_thread_t tid1 = RT_NULL; + +// /* 线程1的入口函数 */ +// static void thread1_entry(void *parameter) +// { +// rt_uint32_t count = 0; // while (1) // { -// rt_pin_write(GPIO_LED_R, PIN_HIGH); -// rt_thread_mdelay(500); -// rt_pin_write(GPIO_LED_R, PIN_LOW); -// rt_thread_mdelay(500); +// /* 线程1采用低优先级运行,一直打印计数值 */ +// rt_kprintf("thread1 count: %d\n", count++); +// rt_thread_mdelay(500); // 延时500毫秒 // } // } -#include -#include "hello.h" +// static char thread2_stack[1024]; +// static struct rt_thread thread2; -int main(void) -{ - while(1) - { - Print_Hello_World(); - rt_thread_mdelay(10000); - } +// /* 线程2入口 */ +// static void thread2_entry(void *param) +// { +// rt_uint32_t count = 0; - return 0; -} +// /* 线程2拥有较高的优先级,以抢占线程1而获得执行 */ +// for (count = 0; count < 10 ; count++) +// { +// /* 线程2打印计数值 */ +// rt_kprintf("thread2 count: %d\n", count); +// } +// rt_kprintf("thread2 exit\n"); + +// /* 线程2运行结束后也将自动被系统脱离 */ +// } + +// /* 线程示例 */ +// int thread_sample(void) +// { +// /* 创建线程1,名称是thread1,入口是thread1_entry */ +// tid1 = rt_thread_create("thread1", +// thread1_entry, RT_NULL, +// THREAD_STACK_SIZE, +// THREAD_PRIORITY, THREAD_TIMESLICE); +// /* 如果获得线程控制块,启动这个线程 */ +// if (tid1 != RT_NULL) +// rt_thread_startup(tid1); + +// /* 初始化线程2,名称是thread2,入口是thread2_entry */ +// rt_thread_init(&thread2, +// "thread2", +// thread2_entry, +// RT_NULL, +// &thread2_stack[0], +// sizeof(thread2_stack), +// THREAD_PRIORITY - 1, THREAD_TIMESLICE); + +// /* 启动线程2 */ +// rt_thread_startup(&thread2); + +// return 0; +// } + +// /* 导出到 msh 命令列表中 */ +// MSH_CMD_EXPORT(thread_sample, thread sample);