yangjie 7 лет назад
Родитель
Сommit
5f76ce4fe3

+ 2 - 2
README.md

@@ -1,2 +1,2 @@
-# kernel-sample
-RT-Thread kernel samples
+# RT-Thread Sample
+[这里介绍本类sample的情况]

+ 58 - 0
SConscript

@@ -0,0 +1,58 @@
+from building import *
+Import('rtconfig')
+
+src   = []
+cwd   = GetCurrentDir()
+group = []
+CPPPATH = []
+
+# add kernel samples.
+if GetDepend('RT_USING_SAMPLE_THREAD'):
+    src += ['thread/thread_sample.c']
+    CPPPATH += [cwd + '/thread']
+
+if GetDepend('RT_USING_SAMPLE_SEMAPHORE'):
+    src += ['semaphore/semaphore_sample.c']
+	src += ['semaphore/producer_consumer.c']
+    CPPPATH += [cwd + '/semaphore']
+
+if GetDepend('RT_USING_SAMPLE_MUTEX'):
+    src += ['mutex/mutex_sample.c']
+	src += ['mutex/pri_inversion.c']
+    CPPPATH += [cwd + '/mutex']
+
+if GetDepend('RT_USING_SAMPLE_MAILBOX'):
+    src += ['mailbox/mailbox_sample.c']
+    CPPPATH += [cwd + '/mailbox']
+
+if GetDepend('RT_USING_SAMPLE_EVENT'):
+    src += ['event/event_sample.c']
+    CPPPATH += [cwd + '/event']
+
+if GetDepend('RT_USING_SAMPLE_MESSAGEQUEUE'):
+    src += ['msgq/msgq_sample.c']
+    CPPPATH += [cwd + '/msgq']
+
+if GetDepend('RT_USING_SAMPLE_TIMER'):
+    src += ['timer/timer_sample.c']
+    CPPPATH += [cwd + '/timer']
+
+if GetDepend('RT_USING_SAMPLE_HEAP'):
+    src += ['dynmem/dynmem_sample.c']
+    CPPPATH += [cwd + '/dynmem']
+
+if GetDepend('RT_USING_SAMPLE_MEMPOOL'):
+    src += ['mempool/memp_sample.c']
+    CPPPATH += [cwd + '/mempool']
+
+if GetDepend('RT_USING_SAMPLE_IDLEHOOK'):
+    src += ['idlehook/idlehook_sample.c']
+    CPPPATH += [cwd + '/idlehook']
+
+if GetDepend('RT_USING_SAMPLE_SIGNAL'):
+    src += ['signal/signal_sample.c']
+    CPPPATH += [cwd + '/signal']
+	
+group = DefineGroup('samples', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 77 - 0
dynmem/README.md

@@ -0,0 +1,77 @@
+# 堆内存的使用
+
+## 介绍
+
+这个程序演示了堆内存的申请和释放操作。
+
+## 程序清单
+
+```{.c}
+/*
+ * 程序清单:堆内存例程
+ *
+ * 这个程序会演示堆内存的申请和释放操作。
+ */
+#include <rtthread.h>
+#include <string.h>
+
+static rt_bool_t mem_check(rt_uint8_t *ptr, rt_uint8_t value, rt_uint32_t len)
+{
+    while (len)
+    {
+        if (*ptr != value)
+            return RT_FALSE;
+        ptr ++;
+        len --;
+    }
+
+    return RT_TRUE;
+}
+
+int heap_malloc(void)
+{
+    rt_uint8_t *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
+
+    ptr1 = rt_malloc(1);
+    ptr2 = rt_malloc(13);
+    ptr3 = rt_malloc(31);
+    ptr4 = rt_malloc(127);
+    ptr5 = rt_malloc(0);
+
+    memset(ptr1, 1, 1);
+    memset(ptr2, 2, 13);
+    memset(ptr3, 3, 31);
+    memset(ptr4, 4, 127);
+
+    if (mem_check(ptr1, 1, 1)   == RT_FALSE)
+        rt_kprintf("mem_check 1 failed\n");
+    if (mem_check(ptr2, 2, 13)  == RT_FALSE)
+        rt_kprintf("mem_check 2 failed\n");
+    if (mem_check(ptr3, 3, 31)  == RT_FALSE)
+        rt_kprintf("mem_check 3 failed\n");
+    if (mem_check(ptr4, 4, 127) == RT_FALSE)
+        rt_kprintf("mem_check 4 failed\n");
+
+    rt_free(ptr4);
+    rt_free(ptr3);
+    rt_free(ptr2);
+    rt_free(ptr1);
+
+    if (ptr5 != RT_NULL)
+    {
+        rt_free(ptr5);
+    }
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(heap_malloc, heap malloc sample);
+```
+
+
+
+
+## 运行结果
+
+没有输出就表示没有错误!

+ 73 - 0
dynmem/dynmem_sample.c

@@ -0,0 +1,73 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+ 
+/*
+ * 程序清单:动态内存管理例程
+ *
+ * 这个程序会创建一个动态的线程,这个线程会动态申请内存并释放
+ */
+#include <rtthread.h>
+
+#define THREAD_PRIORITY      25
+#define THREAD_STACK_SIZE    512
+#define THREAD_TIMESLICE     5
+
+/* 线程入口 */
+void thread1_entry(void *parameter)
+{
+    int i;
+    char *ptr = RT_NULL; /* 内存块的指针 */
+
+    for (i = 0; ; i++)
+    {
+        /* 每次分配 (1 << i) 大小字节数的内存空间 */
+        ptr = rt_malloc(1 << i);
+
+        /* 如果分配成功 */
+        if (ptr != RT_NULL)
+        {
+            rt_kprintf("get memory :%d byte\n", (1 << i));
+            /* 释放内存块 */
+            rt_free(ptr);
+            rt_kprintf("free memory :%d byte\n", (1 << i));
+            ptr = RT_NULL;
+        }
+        else
+        {
+            rt_kprintf("try to get %d byte memory failed!\n", (1 << i));
+            return;
+        }
+    }
+}
+
+int dynmem_sample(void)
+{
+    rt_thread_t tid;
+
+    /* 创建线程1 */
+    tid = rt_thread_create("t1",
+                           thread1_entry, RT_NULL,
+                           THREAD_STACK_SIZE,
+                           THREAD_PRIORITY,
+                           THREAD_TIMESLICE);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        rt_kprintf("create t1 failed");
+        return -1;
+    }
+
+    return 0;
+}
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(dynmem_sample, dynmem sample);

+ 146 - 0
event/README.md

@@ -0,0 +1,146 @@
+# 事件的使用 #
+
+## 介绍 ##
+
+这个例程展示了如何在RT-Thread里使用事件。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:事件例程
+ *
+ * 程序会创建3个动态线程及初始化一个静态事件对象
+ * 一个线程等待于事件对象上以接收事件;
+ * 一个线程定时发送事件 (事件3)
+ * 一个线程定时发送事件 (事件5)
+*/
+#include <rtthread.h>
+
+/* 事件控制块 */
+static struct rt_event event;
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread1_stack[1024];
+static struct rt_thread thread1;
+
+/* 线程1入口函数 */
+static void thread1_entry(void *param)
+{
+    rt_uint32_t e;
+
+    /* receive first event */
+    if (rt_event_recv(&event, ((1 << 3) | (1 << 5)),
+                      RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+                      RT_WAITING_FOREVER, &e) == RT_EOK)
+    {
+        rt_kprintf("thread1: AND recv event 0x%x\n", e);
+    }
+
+    rt_kprintf("thread1: delay 1s to prepare second event\n");
+    rt_thread_delay(RT_TICK_PER_SECOND);
+
+    /* receive second event */
+    if (rt_event_recv(&event, ((1 << 3) | (1 << 5)),
+                      RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+                      RT_WAITING_FOREVER, &e) == RT_EOK)
+    {
+        rt_kprintf("thread1: OR recv event 0x%x\n", e);
+    }
+    rt_kprintf("thread1 leave.\n");
+}
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+/* 线程2入口 */
+static void thread2_entry(void *param)
+{
+    rt_kprintf("thread2: send event1\n");
+    rt_event_send(&event, (1 << 3));
+    rt_kprintf("thread2 leave.\n");
+}
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread3_stack[1024];
+struct rt_thread thread3;
+/* 线程3入口函数 */
+static void thread3_entry(void *param)
+{
+    rt_kprintf("thread3: send event2\n");
+    rt_event_send(&event, (1 << 5));
+
+    rt_thread_delay(20);
+
+    rt_kprintf("thread3: send event2\n");
+    rt_event_send(&event, (1 << 5));
+
+    rt_kprintf("thread3 leave.\n");
+}
+
+int event_sample(void)
+{
+    rt_err_t result;
+
+    /* 初始化事件对象 */
+    result = rt_event(&event, "event", RT_IPC_FLAG_FIFO);
+    if (result != RT_EOK)
+    {
+        rt_kprintf("init event failed.\n");
+        return -1;
+    }
+
+    rt_thread(&thread1,
+                   "thread1",
+                   thread1_entry,
+                   RT_NULL,
+                   &thread1_stack[0],
+                   sizeof(thread1_stack), 8, 50);
+    rt_thread_startup(&thread1);
+
+
+    rt_thread(&thread2,
+                   "thread2",
+                   thread2_entry,
+                   RT_NULL,
+                   &thread2_stack[0],
+                   sizeof(thread2_stack), 9, 5);
+    rt_thread_startup(&thread2);
+
+
+    rt_thread(&thread3,
+                   "thread3",
+                   thread3_entry,
+                   RT_NULL,
+                   &thread3_stack[0],
+                   sizeof(thread3_stack), 10, 5);
+    rt_thread_startup(&thread3);
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(event_sample, event sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jul 17 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >ev
+event_sample
+msh >event_sample
+thread2: send event1
+thread2 leave.
+thread3: send event2
+thread1: AND recv event 0x28
+thread1: delay 1s to prepare second event
+msh >thread3: send event2
+thread3 leave.
+thread1: OR recv event 0x20
+thread1 leave.
+```
+

+ 114 - 0
event/event_sample.c

@@ -0,0 +1,114 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:事件例程
+ *
+ * 程序会初始化2个线程及初始化一个静态事件对象
+ * 一个线程等待于事件对象上以接收事件;
+ * 一个线程定时发送事件 (事件3/事件5)
+*/
+#include <rtthread.h>
+
+#define THREAD_PRIORITY      9
+#define THREAD_TIMESLICE     5
+
+#define EVENT_FLAG3 (1 << 3)
+#define EVENT_FLAG5 (1 << 5)
+
+/* 事件控制块 */
+static struct rt_event event;
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread1_stack[1024];
+static struct rt_thread thread1;
+
+/* 线程1入口函数 */
+static void thread1_recv_event(void *param)
+{
+    rt_uint32_t e;
+
+    /* 第一次接收事件,事件3或事件5任意一个可以触发线程1,接收完后清除事件标志 */
+    if (rt_event_recv(&event, (EVENT_FLAG3 | EVENT_FLAG5),
+                      RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
+                      RT_WAITING_FOREVER, &e) == RT_EOK)
+    {
+        rt_kprintf("thread1: OR recv event 0x%x\n", e);
+    }
+
+    rt_kprintf("thread1: delay 1s to prepare the second event\n");
+    rt_thread_mdelay(1000);
+
+    /* 第二次接收事件,事件3和事件5均发生时才可以触发线程1,接收完后清除事件标志 */
+    if (rt_event_recv(&event, (EVENT_FLAG3 | EVENT_FLAG5),
+                      RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
+                      RT_WAITING_FOREVER, &e) == RT_EOK)
+    {
+        rt_kprintf("thread1: AND recv event 0x%x\n", e);
+    }
+    rt_kprintf("thread1 leave.\n");
+}
+
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+
+/* 线程2入口 */
+static void thread2_send_event(void *param)
+{
+    rt_kprintf("thread2: send event3\n");
+    rt_event_send(&event, EVENT_FLAG3);
+    rt_thread_mdelay(200);
+
+    rt_kprintf("thread2: send event5\n");
+    rt_event_send(&event, EVENT_FLAG5);
+    rt_thread_mdelay(200);
+
+    rt_kprintf("thread2: send event3\n");
+    rt_event_send(&event, EVENT_FLAG3);
+    rt_kprintf("thread2 leave.\n");
+}
+
+int event_sample(void)
+{
+    rt_err_t result;
+
+    /* 初始化事件对象 */
+    result = rt_event_init(&event, "event", RT_IPC_FLAG_FIFO);
+    if (result != RT_EOK)
+    {
+        rt_kprintf("init event failed.\n");
+        return -1;
+    }
+
+    rt_thread_init(&thread1,
+                   "thread1",
+                   thread1_recv_event,
+                   RT_NULL,
+                   &thread1_stack[0],
+                   sizeof(thread1_stack),
+                   THREAD_PRIORITY - 1, THREAD_TIMESLICE);
+    rt_thread_startup(&thread1);
+
+    rt_thread_init(&thread2,
+                   "thread2",
+                   thread2_send_event,
+                   RT_NULL,
+                   &thread2_stack[0],
+                   sizeof(thread2_stack),
+                   THREAD_PRIORITY, THREAD_TIMESLICE);
+    rt_thread_startup(&thread2);
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(event_sample, event sample);

+ 155 - 0
idlehook/README.md

@@ -0,0 +1,155 @@
+# 空闲任务钩子的使用 #
+
+## 介绍 ##
+
+这个例程展示了如何在RT-Thread里使用空闲任务钩子。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:空闲任务钩子例程
+ *
+ * 这个例程设置了一个空闲任务钩子用于计算CPU使用率,并创建一个线程循环打印CPU使用率
+ * 通过修改CPU使用率打印线程中的休眠tick时间可以看到不同的CPU使用率
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#define THREAD_PRIORITY      25
+#define THREAD_STACK_SIZE    512
+#define THREAD_TIMESLICE     5
+
+/* 指向线程控制块的指针 */
+static rt_thread_t tid = RT_NULL;
+
+#define CPU_USAGE_CALC_TICK    10
+#define CPU_USAGE_LOOP        100
+
+static rt_uint8_t  cpu_usage_major = 0, cpu_usage_minor = 0;
+
+/* 记录CPU使用率为0时的总count数 */
+static rt_uint32_t total_count = 0;
+
+/* 空闲任务钩子函数 */
+static void cpu_usage_idle_hook()
+{
+    rt_tick_t tick;
+    rt_uint32_t count;
+    volatile rt_uint32_t loop;
+
+    if (total_count == 0)
+    {
+        /* 获取 total_count */
+        rt_enter_critical();
+        tick = rt_tick_get();
+        while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
+        {
+            total_count ++;
+            loop = 0;
+            while (loop < CPU_USAGE_LOOP) loop ++;
+        }
+        rt_exit_critical();
+    }
+
+    count = 0;
+    /* 计算CPU使用率 */
+    tick = rt_tick_get();
+    while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
+    {
+        count ++;
+        loop  = 0;
+        while (loop < CPU_USAGE_LOOP) loop ++;
+    }
+
+    /* 计算整数百分比整数部分和小数部分 */
+    if (count < total_count)
+    {
+        count = total_count - count;
+        cpu_usage_major = (count * 100) / total_count;
+        cpu_usage_minor = ((count * 100) % total_count) * 100 / total_count;
+    }
+    else
+    {
+        total_count = count;
+
+        /* CPU使用率为0 */
+        cpu_usage_major = 0;
+        cpu_usage_minor = 0;
+    }
+}
+
+void cpu_usage_get(rt_uint8_t *major, rt_uint8_t *minor)
+{
+    RT_ASSERT(major != RT_NULL);
+    RT_ASSERT(minor != RT_NULL);
+
+    *major = cpu_usage_major;
+    *minor = cpu_usage_minor;
+}
+
+/* CPU使用率打印线程入口 */
+static void thread_entry(void *parameter)
+{
+    rt_uint8_t major, minor;
+
+    while (1)
+    {
+        cpu_usage_get(&major, &minor);
+        rt_kprintf("cpu usage: %d.%d%\n", major, minor);
+
+        /* 休眠50个OS Tick */
+        /* 手动修改此处休眠 tick 时间,可以模拟实现不同的CPU使用率 */
+        rt_thread_delay(50);
+    }
+}
+
+int cpu_usage()
+{
+    /* 设置空闲线程钩子 */
+    rt_thread_idle_sethook(cpu_usage_idle_hook);
+
+    /* 创建线程 */
+    tid = rt_thread_create("thread",
+                           thread_entry, RT_NULL, /* 线程入口是thread_entry, 入口参数是RT_NULL */
+                           THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (tid != RT_NULL)
+        rt_thread_startup(tid);
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(cpu_usage, idle hook sample);
+```
+
+## 运行结果 ##
+仿真运行后,控制台一直循环输出打印CPU使用率:
+
+```
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.2%
+cpu usage: 0.0%
+cpu usage: 0.2%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.2%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.2%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.0%
+cpu usage: 0.2%
+cpu usage: 0.2%
+cpu usage: 0.0%
+```
+
+## 说明 ##
+本例程设置了一个空闲任务钩子用于计算CPU使用率,并创建一个线程循环打印CPU使用率。通过修改CPU使用率打印线程中的休眠tick时间可以看到不同的CPU使用率

+ 85 - 0
idlehook/idlehook_sample.c

@@ -0,0 +1,85 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */  
+
+/*
+ * 程序清单:空闲任务钩子例程
+ *
+ * 这个例程创建一个线程,通过延时进入空闲任务钩子,用于打印进入空闲钩子的次数
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+
+#define THREAD_PRIORITY      20
+#define THREAD_STACK_SIZE    1024
+#define THREAD_TIMESLICE     5
+
+/* 指向线程控制块的指针 */
+static rt_thread_t tid = RT_NULL;
+
+/* 空闲函数钩子函数执行次数 */
+volatile static int hook_times = 0;
+
+/* 空闲任务钩子函数 */
+static void idle_hook()
+{
+    if (0 == (hook_times % 10000))
+    {
+        rt_kprintf("enter idle hook %d times.\n", hook_times);
+    }
+
+    rt_enter_critical();
+    hook_times++;
+    rt_exit_critical();
+}
+
+/* 线程入口 */
+static void thread_entry(void *parameter)
+{
+    int i = 5;
+    while (i--)
+    {
+        rt_kprintf("enter thread1.\n");
+        rt_enter_critical();
+        hook_times = 0;
+        rt_exit_critical();
+
+        /* 休眠500ms */
+        rt_kprintf("thread1 delay 50 OS Tick.\n", hook_times);
+        rt_thread_mdelay(500);
+    }
+    rt_kprintf("delete idle hook.\n");
+    rt_thread_idle_delhook(idle_hook);
+    rt_kprintf("thread1 finish.\n");
+}
+
+int idle_hook_sample(void)
+{
+    /* 设置空闲线程钩子 */
+    rt_thread_idle_sethook(idle_hook);
+
+    /* 创建线程 */
+    tid = rt_thread_create("thread1",
+                           thread_entry, RT_NULL, /* 线程入口是thread_entry, 入口参数是RT_NULL */
+                           THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+    else
+    {
+        rt_kprintf("create thread1 failed");
+        return -1;
+    }
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(idle_hook_sample, idle hook sample);

+ 85 - 0
interrupt/README.md

@@ -0,0 +1,85 @@
+# 使用开关中断进行线程间同步
+
+## 介绍
+
+这个例程展示了使用开关中断进行线程间同步。
+
+# 程序清单
+
+```{.c}
+/* 代码清单:关闭中断进行全局变量的访问 */
+#include <rthw.h>
+#include <rtthread.h>
+
+/* 同时访问的全局变量 */
+static rt_uint32_t cnt;
+void thread_entry(void* parameter)
+{
+    rt_uint32_t no;
+    rt_uint32_t level;
+
+    no = (rt_uint32_t) parameter;
+    while(1)
+    {
+        /* 关闭中断 */
+        level = rt_hw_interrupt_disable();
+        cnt += no;
+        /* 恢复中断 */
+        rt_hw_interrupt_enable(level);
+
+        rt_kprintf("thread[%d]'s counter is %d\n", no, cnt);
+        rt_thread_delay(no);
+    }
+}
+
+/* 用户应用程序入口 */
+void interrupt_sample()
+{
+    rt_thread_t thread;
+
+    /* 创建t1线程 */
+    thread = rt_thread_create("t1", thread_entry, (void*)10,
+        512, 10, 5);
+    if (thread != RT_NULL) rt_thread_startup(thread);
+
+    /* 创建t2线程 */
+    thread = rt_thread_create("t2", thread_entry, (void*)20,
+        512, 20, 5);
+    if (thread != RT_NULL) rt_thread_startup(thread);
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(interrupt_sample, interrupt sample);
+```
+# 运行结果
+
+ ```{.c}
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jun 14 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >inter
+interrupt_sample
+msh >interrupt_sample
+thread[10]'s counter is 10
+msh >thread[20]'s counter is 30
+thread[10]'s counter is 40
+thread[10]'s counter is 50
+thread[20]'s counter is 70
+thread[10]'s counter is 80
+thread[10]'s counter is 90
+thread[20]'s counter is 110
+thread[10]'s counter is 120
+thread[10]'s counter is 130
+thread[20]'s counter is 150
+thread[10]'s counter is 160
+thread[10]'s counter is 170
+thread[20]'s counter is 190
+thread[10]'s counter is 200
+thread[10]'s counter is 210
+thread[20]'s counter is 230
+thread[10]'s counter is 240
+thread[10]'s counter is 250
+thread[20]'s counter is 270
+...
+ ```

+ 76 - 0
interrupt/interrupt_sample.c

@@ -0,0 +1,76 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+ 
+/* 程序清单:关闭中断进行全局变量的访问 */
+#include <rthw.h>
+#include <rtthread.h>
+
+#define THREAD_PRIORITY      20
+#define THREAD_STACK_SIZE    512
+#define THREAD_TIMESLICE     5
+
+/* 同时访问的全局变量 */
+static rt_uint32_t cnt;
+void thread_entry(void *parameter)
+{
+    rt_uint32_t no;
+    rt_uint32_t level;
+
+    no = (rt_uint32_t) parameter;
+    while (1)
+    {
+        /* 关闭中断 */
+        level = rt_hw_interrupt_disable();
+        cnt += no;
+        /* 恢复中断 */
+        rt_hw_interrupt_enable(level);
+
+        rt_kprintf("protect thread[%d]'s counter is %d\n", no, cnt);
+        rt_thread_mdelay(no * 10);
+    }
+}
+
+/* 用户应用程序入口 */
+int interrupt_sample(void)
+{
+    rt_thread_t thread;
+
+    /* 创建t1线程 */
+    thread = rt_thread_create("t1", thread_entry, (void *)10,
+                              THREAD_STACK_SIZE,
+                              THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create t1 failed");
+        return -1;
+    }
+
+    /* 创建t2线程 */
+    thread = rt_thread_create("t2", thread_entry, (void *)20,
+                              THREAD_STACK_SIZE,
+                              THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (thread != RT_NULL)
+    {
+        rt_thread_startup(thread);
+    }
+    else
+    {
+        rt_kprintf("create t2 failed");
+        return -1;
+    }
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(interrupt_sample, interrupt sample);

+ 157 - 0
mailbox/README.md

@@ -0,0 +1,157 @@
+# 邮箱的使用 #
+
+## 介绍 ##
+
+这个例程展示了如何在RT-Thread里使用邮箱服务。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:邮箱例程
+ *
+ * 这个程序会创建2个动态线程,一个静态的邮箱对象,其中一个线程往邮箱中发送邮件,
+ * 一个线程往邮箱中收取邮件。
+ */
+#include <rtthread.h>
+
+/* 邮箱控制块 */
+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";
+
+ALIGN(RT_ALIGN_SIZE)
+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_uint32_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;
+
+            /* 延时10个OS Tick */
+            rt_thread_delay(10);
+        }
+    }
+    /* 执行邮箱对象脱离 */
+    rt_mb_detach(&mb);
+}
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+/* 线程2入口 */
+static void thread2_entry(void *parameter)
+{
+    rt_uint8_t count;
+
+    count = 0;
+    while (count < 10)
+    {
+        count ++;
+        if (count & 0x1)
+        {
+            /* 发送mb_str1地址到邮箱中 */
+            rt_mb_send(&mb, (rt_uint32_t)&mb_str1[0]);
+        }
+        else
+        {
+            /* 发送mb_str2地址到邮箱中 */
+            rt_mb_send(&mb, (rt_uint32_t)&mb_str2[0]);
+        }
+
+        /* 延时20个OS Tick */
+        rt_thread_delay(20);
+    }
+
+    /* 发送邮件告诉线程1,线程2已经运行结束 */
+    rt_mb_send(&mb, (rt_uint32_t)&mb_str3[0]);
+}
+
+int mailbox_sample()
+{
+    rt_err_t result;
+
+    /* 初始化一个mailbox */
+    result = rt_mb(&mb,
+                        "mbt",                      /* 名称是mbt */
+                        &mb_pool[0],                /* 邮箱用到的内存池是mb_pool */
+                        sizeof(mb_pool) / 4,        /* 邮箱中的邮件数目,因为一封邮件占4字节 */
+                        RT_IPC_FLAG_FIFO);          /* 采用FIFO方式进行线程等待 */
+    if (result != RT_EOK)
+    {
+        rt_kprintf("init mailbox failed.\n");
+        return -1;
+    }
+
+    rt_thread(&thread1,
+                   "thread1",
+                   thread1_entry,
+                   RT_NULL,
+                   &thread1_stack[0],
+                   sizeof(thread1_stack), 10, 5);
+    rt_thread_startup(&thread1);
+
+    rt_thread(&thread2,
+                   "thread2",
+                   thread2_entry,
+                   RT_NULL,
+                   &thread2_stack[0],
+                   sizeof(thread2_stack), 10, 5);
+    rt_thread_startup(&thread2);
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(mailbox_sample, mailbox sample);
+```
+
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jul 17 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >mail
+mailbox_sample
+msh >mailbox_sample
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:I'm a mail!
+msh >thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:this is another mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:I'm a mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:this is another mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:I'm a mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:this is another mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:I'm a mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:this is another mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:I'm a mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:this is another mail!
+thread1: try to recv a mail
+thread1: get a mail from mailbox, the content:over
+```

+ 128 - 0
mailbox/mailbox_sample.c

@@ -0,0 +1,128 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:邮箱例程
+ *
+ * 这个程序会创建2个动态线程,一个静态的邮箱对象,其中一个线程往邮箱中发送邮件,
+ * 一个线程往邮箱中收取邮件。
+ */
+#include <rtthread.h>
+
+#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";
+
+ALIGN(RT_ALIGN_SIZE)
+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_uint32_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);
+}
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+
+/* 线程2入口 */
+static void thread2_entry(void *parameter)
+{
+    rt_uint8_t count;
+
+    count = 0;
+    while (count < 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) / 4,        /* 邮箱中的邮件数目,因为一封邮件占4字节 */
+                        RT_IPC_FLAG_FIFO);          /* 采用FIFO方式进行线程等待 */
+    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);

+ 164 - 0
mempool/README.md

@@ -0,0 +1,164 @@
+# 内存池的使用 #
+
+## 介绍 ##
+
+这个例程展示了如何在RT-Thread里使用内存池。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:内存池例程
+ *
+ * 这个程序会创建一个静态的内存池对象,2个动态线程。两个线程会试图分别从内存池中获得
+ * 内存块
+ */
+#include <rtthread.h>
+
+static rt_uint8_t *ptr[48];
+static rt_uint8_t mempool[4096];
+static struct rt_mempool mp;
+
+#define THREAD_PRIORITY      25
+#define THREAD_STACK_SIZE    512
+#define THREAD_TIMESLICE     5
+
+/* 指向线程控制块的指针 */
+static rt_thread_t tid1 = RT_NULL;
+static rt_thread_t tid2 = RT_NULL;
+
+/* 线程1入口 */
+static void thread1_entry(void *parameter)
+{
+    int i, count = 0;
+    char *block;
+
+    while (1)
+    {
+        for (i = 0; i < 48; i++)
+        {
+            /* 申请内存块 */
+            if (ptr[i] == RT_NULL)
+            {
+                ptr[i] = rt_mp_alloc(&mp, RT_WAITING_FOREVER);
+                rt_kprintf("allocate No.%d\n", i);
+            }
+        }
+
+        /* 继续申请一个内存块,因为已经没有内存块,线程应该被挂起 */
+        block = rt_mp_alloc(&mp, RT_WAITING_FOREVER);
+        rt_kprintf("allocate the block mem\n");
+        /* 释放这个内存块 */
+        rt_mp_free(block);
+        block = RT_NULL;
+
+        /* 休眠10个OS Tick */
+        rt_thread_delay(10);
+
+        /* 循环10次后,退出线程1 */
+        if (count++ >= 10) break;
+    }
+}
+
+/* 线程2入口,线程2的优先级比线程1低,应该线程1先获得执行。*/
+static void thread2_entry(void *parameter)
+{
+    int i, count = 0;
+
+    while (1)
+    {
+        rt_kprintf("try to release block\n");
+
+        for (i = 0 ; i < 48; i ++)
+        {
+            /* 释放所有分配成功的内存块 */
+            if (ptr[i] != RT_NULL)
+            {
+                rt_kprintf("release block %d\n", i);
+
+                rt_mp_free(ptr[i]);
+                ptr[i] = RT_NULL;
+            }
+        }
+
+        /* 休眠10个OS Tick */
+        rt_thread_delay(10);
+
+        /* 循环10次后,退出线程2 */
+        if (count++ >= 10) break;
+    }
+}
+
+int mempool_sample()
+{
+    int i;
+    for (i = 0; i < 48; i ++) ptr[i] = RT_NULL;
+
+    /* 初始化内存池对象 */
+    rt_mp(&mp, "mp1", &mempool[0], sizeof(mempool), 80);
+
+    /* 创建线程1 */
+    tid1 = rt_thread_create("t1",
+                            thread1_entry, RT_NULL, /* 线程入口是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, /* 线程入口是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(mempool_sample, mempool sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jul 17 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >mem
+mempool_sample
+msh >mempool_sample
+msh >allocate No.0
+allocate No.1
+allocate No.2
+...
+allocate No.47
+try to release block
+release block 0
+allocate the block mem
+release block 1
+release block 2
+...
+release block 47
+allocate No.0
+allocate No.1
+allocate No.2
+...
+allocate No.47
+try to release block
+release block 0
+allocate the block mem
+release block 1
+...
+release block 47
+allocate No.0
+allocate No.1
+allocate No.2
+...
+allocate No.47
+try to release block
+release block 0
+allocate the block mem
+release block 1
+...
+```

+ 106 - 0
mempool/memp_sample.c

@@ -0,0 +1,106 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:内存池例程
+ *
+ * 这个程序会创建一个静态的内存池对象,2个动态线程。
+ * 一个线程会试图从内存池中获得内存块,另一个线程释放内存块
+ * 内存块
+ */
+#include <rtthread.h>
+#include <rtdef.h>
+static rt_uint8_t *ptr[50];
+static rt_uint8_t mempool[4096];
+static struct rt_mempool mp;
+
+#define THREAD_PRIORITY      25
+#define THREAD_STACK_SIZE    512
+#define THREAD_TIMESLICE     5
+
+/* 指向线程控制块的指针 */
+static rt_thread_t tid1 = RT_NULL;
+static rt_thread_t tid2 = RT_NULL;
+
+/* 线程1入口 */
+static void thread1_mp_alloc(void *parameter)
+{
+    int i;
+    for (i = 0 ; i < 50 ; i++)
+    {
+        if (ptr[i] == RT_NULL)
+        {
+            /* 试图申请内存块50次,当申请不到内存块时,
+               线程1挂起,转至线程2运行 */
+            ptr[i] = rt_mp_alloc(&mp, RT_WAITING_FOREVER);
+            if (ptr[i] != RT_NULL)
+                rt_kprintf("allocate No.%d\n", i);
+        }
+    }
+}
+
+/* 线程2入口,线程2的优先级比线程1低,应该线程1先获得执行。*/
+static void thread2_mp_release(void *parameter)
+{
+    int i;
+
+    rt_kprintf("thread2 try to release block\n");
+    for (i = 0; i < 50 ; i++)
+    {
+        /* 释放所有分配成功的内存块 */
+        if (ptr[i] != RT_NULL)
+        {
+            rt_kprintf("release block %d\n", i);
+            rt_mp_free(ptr[i]);
+            ptr[i] = RT_NULL;
+        }
+    }
+}
+
+int mempool_sample(void)
+{
+    int i;
+    for (i = 0; i < 50; i ++) ptr[i] = RT_NULL;
+
+    /* 初始化内存池对象 */
+    rt_mp_init(&mp, "mp1", &mempool[0], sizeof(mempool), 80);
+
+    /* 创建线程1:申请内存池 */
+    tid1 = rt_thread_create("t1", thread1_mp_alloc, RT_NULL,
+                            THREAD_STACK_SIZE,
+                            THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (tid1 != RT_NULL)
+    {
+        rt_thread_startup(tid1);
+    }
+    else
+    {
+        rt_kprintf("create t1 failed");
+        return -1;
+    }
+
+    /* 创建线程2:释放内存池*/
+    tid2 = rt_thread_create("t2", thread2_mp_release, RT_NULL,
+                            THREAD_STACK_SIZE,
+                            THREAD_PRIORITY + 1, THREAD_TIMESLICE);
+    if (tid2 != RT_NULL)
+    {
+        rt_thread_startup(tid2);
+    }
+    else
+    {
+        rt_kprintf("create t2 failed");
+        return -1;
+    }
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(mempool_sample, mempool sample);

+ 179 - 0
msgq/README.md

@@ -0,0 +1,179 @@
+# 消息队列的使用 #
+
+## 介绍 ##
+
+这个例程展示了如何在RT-Thread里使用消息队列。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:消息队列例程
+ *
+ * 这个程序会创建2个动态线程,一个线程会从消息队列中收取消息;一个线程会定时给消
+ * 息队列发送 普通消息和紧急消息。
+ */
+#include <rtthread.h>
+
+/* 消息队列控制块 */
+static struct rt_messagequeue mq;
+/* 消息队列中用到的放置消息的内存池 */
+static rt_uint8_t msg_pool[2048];
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread1_stack[1024];
+static struct rt_thread thread1;
+/* 线程1入口函数 */
+static void thread1_entry(void *parameter)
+{
+    rt_uint8_t buf = 0;
+
+    while (1)
+    {
+        /* 从消息队列中接收消息 */
+        if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK)
+        {
+            rt_kprintf("thread1: recv msg from msg queue, the content:%d\n", buf);
+            if (buf == 49)
+            {
+                break;
+            }
+        }
+        /* 延时100ms */
+        rt_thread_delay(rt_tick_from_millisecond(100));
+    }
+    rt_kprintf("thread1: detach mq \n");
+    rt_mq_detach(&mq);
+}
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+/* 线程2入口 */
+static void thread2_entry(void *parameter)
+{
+    int result;
+    rt_uint8_t buf = 0;
+    while (1)
+    {
+        if (buf == 25)
+        {
+            /* 发送紧急消息到消息队列中 */
+            result = rt_mq_urgent(&mq, &buf, 1);
+            if (result != RT_EOK)
+            {
+                rt_kprintf("rt_mq_urgent ERR\n");
+            }
+            rt_kprintf("thread2: send urgent message - %d\n", buf);
+        }
+        else if (buf >= 50)/* 发送50次消息之后退出 */
+        {
+            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 - %d\n", buf);
+        }
+        buf++;
+        /* 延时10ms */
+        rt_thread_delay(rt_tick_from_millisecond(10));
+    }
+}
+
+/* 消息队列示例的初始化 */
+int messagequeue_sample()
+{
+    rt_err_t result;
+
+    /* 初始化消息队列 */
+    result = rt_mq(&mq,
+                        "mqt",
+                        &msg_pool[0],               /* 内存池指向msg_pool */
+                        1,                          /* 每个消息的大小是 1 字节 */
+                        sizeof(msg_pool),           /* 内存池的大小是msg_pool的大小 */
+                        RT_IPC_FLAG_FIFO);          /* 如果有多个线程等待,按照先来先得到的方法分配消息 */
+
+    if (result != RT_EOK)
+    {
+        rt_kprintf("init message queue failed.\n");
+        return -1;
+    }
+
+    rt_thread(&thread1,
+                   "thread1",
+                   thread1_entry,
+                   RT_NULL,
+                   &thread1_stack[0],
+                   sizeof(thread1_stack), 25, 5);
+    rt_thread_startup(&thread1);
+
+    rt_thread(&thread2,
+                   "thread2",
+                   thread2_entry,
+                   RT_NULL,
+                   &thread2_stack[0],
+                   sizeof(thread2_stack), 25, 5);
+    rt_thread_startup(&thread2);
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(messagequeue_sample, messagequeue sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jun 14 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >mes
+messagequeue_sample
+msh >messagequeue_sample
+msh >thread2: send message - 0
+thread1: recv msg from msg queue, the content:0
+thread2: send message - 1
+thread2: send message - 2
+...
+thread2: send message - 9
+thread1: recv msg from msg queue, the content:1
+thread2: send message – 10
+...
+thread2: send message - 19
+thread1: recv msg from msg queue, the content:2
+thread2: send message - 20
+...
+thread2: send message - 24
+thread2: send urgent message - 25
+thread2: send message - 26
+...
+thread2: send message - 29
+thread1: recv msg from msg queue, the content:25
+thread2: send message - 30
+...
+thread2: send message - 39
+thread1: recv msg from msg queue, the content:3
+thread2: send message - 40
+...
+thread2: send message - 49
+thread1: recv msg from msg queue, the content:4
+message queue stop send, thread2 quit
+thread1: recv msg from msg queue, the content:5
+thread1: recv msg from msg queue, the content:6
+...
+thread1: recv msg from msg queue, the content:49
+thread1: detach mq 
+
+```
+
+

+ 139 - 0
msgq/msgq_sample.c

@@ -0,0 +1,139 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:消息队列例程
+ *
+ * 这个程序会创建2个动态线程,一个线程会从消息队列中收取消息;一个线程会定时给消
+ * 息队列发送 普通消息和紧急消息。
+ */
+#include <rtthread.h>
+
+/* 消息队列控制块 */
+static struct rt_messagequeue mq;
+/* 消息队列中用到的放置消息的内存池 */
+static rt_uint8_t msg_pool[2048];
+
+ALIGN(RT_ALIGN_SIZE)
+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) == RT_EOK)
+        {
+            rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", buf);
+            if (cnt == 19)
+            {
+                break;
+            }
+        }
+        /* 延时100ms */
+        cnt++;
+        rt_thread_mdelay(50);
+    }
+    rt_kprintf("thread1: detach mq \n");
+    rt_mq_detach(&mq);
+}
+
+ALIGN(RT_ALIGN_SIZE)
+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 messagequeue_sample()
+{
+    rt_err_t result;
+
+    /* 初始化消息队列 */
+    result = rt_mq_init(&mq,
+                        "mqt",
+                        &msg_pool[0],               /* 内存池指向msg_pool */
+                        1,                          /* 每个消息的大小是 1 字节 */
+                        sizeof(msg_pool),           /* 内存池的大小是msg_pool的大小 */
+                        RT_IPC_FLAG_FIFO);          /* 如果有多个线程等待,按照先来先得到的方法分配消息 */
+
+    if (result != RT_EOK)
+    {
+        rt_kprintf("init message queue failed.\n");
+        return -1;
+    }
+
+    rt_thread_init(&thread1,
+                   "thread1",
+                   thread1_entry,
+                   RT_NULL,
+                   &thread1_stack[0],
+                   sizeof(thread1_stack), 25, 5);
+    rt_thread_startup(&thread1);
+
+    rt_thread_init(&thread2,
+                   "thread2",
+                   thread2_entry,
+                   RT_NULL,
+                   &thread2_stack[0],
+                   sizeof(thread2_stack), 25, 5);
+    rt_thread_startup(&thread2);
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(messagequeue_sample, messagequeue sample);

+ 203 - 0
mutex/README.md

@@ -0,0 +1,203 @@
+# 互斥量的使用 #
+
+## 介绍 ##
+
+这个例程展示了如何在RT-Thread里使用互斥量。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:互斥锁例程
+ *
+ * 互斥锁是一种保护共享资源的方法。当一个线程拥有互斥锁的时候,另一个线程若是等待锁,
+ * 则其就会被挂起,从而保证只有一个线程会操作共享数据。
+ *
+ */
+#include <rtthread.h>
+
+/* 互斥量控制块 */
+static struct rt_mutex static_mutex;
+/* 指向互斥量的指针 */
+static rt_mutex_t dynamic_mutex = RT_NULL;
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread1_stack[1024];
+static struct rt_thread thread1;
+static void rt_thread_entry1(void *parameter)
+{
+    rt_err_t result;
+    rt_tick_t tick;
+
+    /* 1. staic mutex demo */
+
+    /* 试图持有互斥量,最大等待10个OS Tick后返回 */
+    rt_kprintf("thread1 try to get static mutex, wait 10 ticks.\n");
+
+    /* 获得当前的OS Tick */
+    tick = rt_tick_get();
+    result = rt_mutex_take(&static_mutex, 10);
+
+    if (result == -RT_ETIMEOUT)
+    {
+        /* 超时后判断是否刚好是10个OS Tick */
+        if (rt_tick_get() - tick != 10)
+        {
+            rt_mutex_detach(&static_mutex);
+            return;
+        }
+        rt_kprintf("thread1 take static mutex timeout\n");
+    }
+    else
+    {
+        /* 线程2持有互斥量,且在相当长的时间后才会释放互斥量,
+         * 因此10个tick后线程1不可能获得 */
+        rt_kprintf("thread1 take a static mutex, failed.\n");
+        rt_mutex_detach(&static_mutex);
+        return;
+    }
+
+    /* 永久等待方式持有互斥量 */
+    rt_kprintf("thread1 try to get static mutex, wait forever.\n");
+    result = rt_mutex_take(&static_mutex, RT_WAITING_FOREVER);
+    if (result != RT_EOK)
+    {
+        /* 不成功则测试失败 */
+        rt_kprintf("thread1 take a static mutex, failed.\n");
+        rt_mutex_detach(&static_mutex);
+        return;
+    }
+
+    rt_kprintf("thread1 take a staic mutex, done.\n");
+
+    /* 脱离互斥量对象 */
+    rt_mutex_detach(&static_mutex);
+
+    /* 2. dynamic mutex test */
+
+    /* 试图持有互斥量,最大等待10个OS Tick后返回 */
+    rt_kprintf("thread1 try to get dynamic mutex, wait 10 ticks.\n");
+
+    tick = rt_tick_get();
+    result = rt_mutex_take(dynamic_mutex, 10);
+    if (result == -RT_ETIMEOUT)
+    {
+        /* 超时后判断是否刚好是10个OS Tick */
+        if (rt_tick_get() - tick != 10)
+        {
+            rt_mutex_delete(dynamic_mutex);
+            return;
+        }
+        rt_kprintf("thread1 take dynamic mutex timeout\n");
+    }
+    else
+    {
+        /* 线程2持有互斥量,且在相当长的时间后才会释放互斥量,
+         * 因此10个tick后线程1不可能获得 */
+        rt_kprintf("thread1 take a dynamic mutex, failed.\n");
+        rt_mutex_delete(dynamic_mutex);
+        return;
+    }
+
+    /* 永久等待方式持有互斥量 */
+    rt_kprintf("thread1 try to get dynamic mutex, wait forever.\n");
+    result = rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
+    if (result != RT_EOK)
+    {
+        /* 不成功则测试失败 */
+        rt_kprintf("thread1 take a dynamic mutex, failed.\n");
+        rt_mutex_delete(dynamic_mutex);
+        return;
+    }
+
+    rt_kprintf("thread1 take a dynamic mutex, done.\n");
+    /* 删除互斥量对象 */
+    rt_mutex_delete(dynamic_mutex);
+}
+
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+static void rt_thread_entry2(void *parameter)
+{
+    /* 1. static mutex test */
+    rt_kprintf("thread2 try to get static mutex\n");
+    rt_mutex_take(&static_mutex, 10);
+    rt_kprintf("thread2 got static mutex\n");
+    rt_thread_delay(RT_TICK_PER_SECOND);
+    rt_kprintf("thread2 release static mutex\n");
+    rt_mutex_release(&static_mutex);
+
+    /* 2. dynamic mutex test */
+    rt_kprintf("thread2 try to get dynamic mutex\n");
+    rt_mutex_take(dynamic_mutex, 10);
+    rt_kprintf("thread2 got dynamic mutex\n");
+    rt_thread_delay(RT_TICK_PER_SECOND);
+    rt_kprintf("thread2 release dynamic mutex\n");
+    rt_mutex_release(dynamic_mutex);
+}
+
+/* 互斥量示例的初始化 */
+int mutex_sample()
+{
+    rt_err_t result;
+
+    /* 初始化静态互斥量 */
+    result = rt_mutex(&static_mutex, "smutex", RT_IPC_FLAG_FIFO);
+    if (result != RT_EOK)
+    {
+        rt_kprintf("init static mutex failed.\n");
+        return -1;
+    }
+
+    /* 创建一个动态互斥量 */
+    dynamic_mutex = rt_mutex_create("dmutex", RT_IPC_FLAG_FIFO);
+    if (dynamic_mutex == RT_NULL)
+    {
+        rt_kprintf("create dynamic mutex failed.\n");
+        return -1;
+    }
+
+    rt_thread(&thread1,
+                   "thread1",
+                   rt_thread_entry1,
+                   RT_NULL,
+                   &thread1_stack[0],
+                   sizeof(thread1_stack), 11, 5);
+    rt_thread_startup(&thread1);
+
+
+    rt_thread(&thread2,
+                   "thread2",
+                   rt_thread_entry2,
+                   RT_NULL,
+                   &thread2_stack[0],
+                   sizeof(thread2_stack), 10, 5);
+    rt_thread_startup(&thread2);
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(mutex_sample, mutex sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jul 17 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >mu 
+mutex_sample
+msh >mutex_sample
+thread1 try to get static mutex, wait 10 ticks.
+thread1 take a static mutex, failed.
+thread2 try to get static mutex
+msh >thread2 got static mutex
+thread2 release static mutex
+thread2 try to get dynamic mutex
+thread2 got dynamic mutex
+thread2 release dynamic mutex
+```

+ 110 - 0
mutex/mutex_sample.c

@@ -0,0 +1,110 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:互斥锁例程
+ *
+ * 互斥锁是一种保护共享资源的方法。当一个线程拥有互斥锁的时候,
+ * 可以保护共享资源不被其他线程破坏。线程1对2个number分别进行加1操作
+ * 线程2也会对number分别进行加1操作。使用互斥量保证2个number值保持一致
+ */
+#include <rtthread.h>
+#define SAMPLE_USE_MUTEX  //打开该则使用互斥量保护线程1对number的操作
+
+#define THREAD_PRIORITY         8
+#define THREAD_TIMESLICE        5
+
+/* 指向互斥量的指针 */
+static rt_mutex_t dynamic_mutex = RT_NULL;
+static rt_uint8_t number1,number2 = 0;
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread1_stack[1024];
+static struct rt_thread thread1;
+static void rt_thread_entry1(void *parameter)
+{
+      while(1)
+      {
+          #ifdef SAMPLE_USE_MUTEX
+          /* 线程1获取到互斥量后,先后对number1、number2进行加1操作,然后释放互斥量 */
+          rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);
+          #endif
+          
+          number1++;
+          rt_thread_mdelay(10);
+          number2++;
+          
+          #ifdef SAMPLE_USE_MUTEX
+          rt_mutex_release(dynamic_mutex);
+          #endif
+       }	    
+}
+
+
+ALIGN(RT_ALIGN_SIZE)
+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_FIFO);
+    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);

+ 167 - 0
mutex/pri_inversion.c

@@ -0,0 +1,167 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:互斥量使用例程
+ *
+ * 这个例子将创建 3 个动态线程以检查持有互斥量时,持有的线程优先级是否
+ * 被调整到等待线程优先级中的最高优先级。
+ *
+ * 线程 1,2,3 的优先级从高到低分别被创建,
+ * 线程 3 先持有互斥量,而后线程 2 试图持有互斥量,此时线程 3 的优先级应该
+ * 被提升为和线程 2 的优先级相同。线程 1 用于检查线程 3 的优先级是否被提升
+ * 为与线程 2的优先级相同。
+ */
+#include <rtthread.h>
+
+/* 指向线程控制块的指针 */
+static rt_thread_t tid1 = RT_NULL;
+static rt_thread_t tid2 = RT_NULL;
+static rt_thread_t tid3 = RT_NULL;
+static rt_mutex_t mutex = RT_NULL;
+
+
+#define THREAD_PRIORITY       10
+#define THREAD_STACK_SIZE     512
+#define THREAD_TIMESLICE    5
+
+/* 线程 1 入口 */
+static void thread1_entry(void *parameter)
+{
+    /* 先让低优先级线程运行 */
+    rt_thread_mdelay(100);
+
+    /* 此时 thread3 持有 mutex,并且 thread2 等待持有 mutex */
+
+    /* 检查 rt_kprintf("the producer generates a number: %d\n", array[set%MAXSEM]); 与 thread3 的优先级情况 */
+    if (tid2->current_priority != tid3->current_priority)
+    {
+        /* 优先级不相同,测试失败 */
+        rt_kprintf("the priority of thread2 is: %d\n", tid2->current_priority);
+        rt_kprintf("the priority of thread3 is: %d\n", tid3->current_priority);
+        rt_kprintf("test failed.\n");
+        return;
+    }
+    else
+    {
+        rt_kprintf("the priority of thread2 is: %d\n", tid2->current_priority);
+        rt_kprintf("the priority of thread3 is: %d\n", tid3->current_priority);
+        rt_kprintf("test OK.\n");
+    }
+}
+
+/* 线程 2 入口 */
+static void thread2_entry(void *parameter)
+{
+    rt_err_t result;
+
+    rt_kprintf("the priority of thread2 is: %d\n", tid2->current_priority);
+
+    /* 先让低优先级线程运行 */
+    rt_thread_mdelay(50);
+
+
+    /*
+     * 试图持有互斥锁,此时 thread3 持有,应把 thread3 的优先级提升
+     * 到 thread2 相同的优先级
+     */
+    result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
+
+    if (result == RT_EOK)
+    {
+        /* 释放互斥锁 */
+        rt_mutex_release(mutex);
+    }
+}
+
+/* 线程 3 入口 */
+static void thread3_entry(void *parameter)
+{
+    rt_tick_t tick;
+    rt_err_t result;
+
+    rt_kprintf("the priority of thread3 is: %d\n", tid3->current_priority);
+
+    result = rt_mutex_take(mutex, RT_WAITING_FOREVER);
+    if (result != RT_EOK)
+    {
+        rt_kprintf("thread3 take a mutex, failed.\n");
+    }
+
+    /* 做一个长时间的循环,总共 50 个 OS Tick */
+    tick = rt_tick_get();
+    while (rt_tick_get() - tick < 50) ;
+
+    rt_mutex_release(mutex);
+}
+
+int pri_inversion(void)
+{
+    /* 创建互斥锁 */
+    mutex = rt_mutex_create("mutex", RT_IPC_FLAG_FIFO);
+    if (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 - 1, THREAD_TIMESLICE);
+    if (tid1 != RT_NULL)
+    {
+        rt_thread_startup(tid1);
+    }
+    else
+    {
+        rt_kprintf("create t1 failed"); 
+        return -1;
+    }
+
+    /* 创建线程 2 */
+    tid2 = rt_thread_create("t2",
+                            thread2_entry, 
+                            RT_NULL, 
+                            THREAD_STACK_SIZE, 
+                            THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (tid2 != RT_NULL)
+    {
+        rt_thread_startup(tid2);
+    }
+    else
+    {
+        rt_kprintf("create t2 failed"); 
+        return -1;
+    }
+
+    /* 创建线程 3 */
+    tid3 = rt_thread_create("t3",
+                            thread3_entry, 
+                            RT_NULL, 
+                            THREAD_STACK_SIZE, 
+                            THREAD_PRIORITY + 1, THREAD_TIMESLICE);
+    if (tid3 != RT_NULL)
+    {
+        rt_thread_startup(tid3);
+    }
+    else
+    {
+        rt_kprintf("create t3 failed"); 
+        return -1;
+    }
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(pri_inversion, prio_inversion sample);

+ 160 - 0
semaphore/README.md

@@ -0,0 +1,160 @@
+# 生产者消费者问题 #
+
+## 介绍 ##
+
+这个例程展示了如何在RT-Thread里实现生产者消费者问题。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:生产者消费者例子
+ *
+ * 这个例子中将创建两个线程用于实现生产者消费者问题
+ */
+#include <rtthread.h>
+
+#define THREAD_PRIORITY       6
+#define THREAD_STACK_SIZE     512
+#define THREAD_TIMESLICE      5
+
+/* 定义最大5个元素能够被产生 */
+#define MAXSEM 5
+
+/* 用于放置生产的整数数组 */
+rt_uint32_t array[MAXSEM];
+/* 指向生产者、消费者在array数组中的读写位置 */
+static rt_uint32_t set, get;
+
+/* 指向线程控制块的指针 */
+static rt_thread_t producer_tid = RT_NULL;
+static rt_thread_t consumer_tid = RT_NULL;
+
+struct rt_semaphore sem_lock;
+struct rt_semaphore sem_empty, sem_full;
+
+/* 生成者线程入口 */
+void producer_thread_entry(void *parameter)
+{
+    int cnt = 0;
+
+    /* 运行10次 */
+    while (cnt < 10)
+    {
+        /* 获取一个空位 */
+        rt_sem_take(&sem_empty, RT_WAITING_FOREVER);
+
+        /* 修改array内容,上锁 */
+        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
+        array[set % MAXSEM] = cnt + 1;
+        rt_kprintf("the producer generates a number: %d\n", array[set % MAXSEM]);
+        set++;
+        rt_sem_release(&sem_lock);
+
+        /* 发布一个满位 */
+        rt_sem_release(&sem_full);
+        cnt++;
+
+        /* 暂停一段时间 */
+        rt_thread_delay(2);
+    }
+
+    rt_kprintf("the producer exit!\n");
+}
+
+/* 消费者线程入口 */
+void consumer_thread_entry(void *parameter)
+{
+    rt_uint32_t no;
+    rt_uint32_t sum;
+
+    /* 第n个线程,由入口参数传进来 */
+    no = (rt_uint32_t)parameter;
+
+    sum = 0;
+    while (1)
+    {
+        /* 获取一个满位 */
+        rt_sem_take(&sem_full, RT_WAITING_FOREVER);
+
+        /* 临界区,上锁进行操作 */
+        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
+        sum += array[get % MAXSEM];
+        rt_kprintf("the consumer[%d] get a number: %d\n", (get % MAXSEM), array[get % MAXSEM]);
+        get++;
+        rt_sem_release(&sem_lock);
+
+        /* 释放一个空位 */
+        rt_sem_release(&sem_empty);
+
+        /* 生产者生产到10个数目,停止,消费者线程相应停止 */
+        if (get == 10) break;
+
+        /* 暂停一小会时间 */
+        rt_thread_delay(5);
+    }
+
+    rt_kprintf("the consumer[%d] sum is %d \n ", no, sum);
+    rt_kprintf("the consumer[%d] exit!\n");
+}
+
+int semaphore_sample()
+{
+    /* 初始化3个信号量 */
+    rt_sem(&sem_lock, "lock",     1,      RT_IPC_FLAG_FIFO);
+    rt_sem(&sem_empty, "empty",    MAXSEM, RT_IPC_FLAG_FIFO);
+    rt_sem(&sem_full, "full",     0,      RT_IPC_FLAG_FIFO);
+
+    /* 创建线程1 */
+    producer_tid = rt_thread_create("producer",
+                                    producer_thread_entry, RT_NULL, /* 线程入口是producer_thread_entry, 入口参数是RT_NULL */
+                                    THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE);
+    if (producer_tid != RT_NULL)
+        rt_thread_startup(producer_tid);
+
+    /* 创建线程2 */
+    consumer_tid = rt_thread_create("consumer",
+                                    consumer_thread_entry, RT_NULL, /* 线程入口是consumer_thread_entry, 入口参数是RT_NULL */
+                                    THREAD_STACK_SIZE, THREAD_PRIORITY + 1, THREAD_TIMESLICE);
+    if (consumer_tid != RT_NULL)
+        rt_thread_startup(consumer_tid);
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(semaphore_sample, semaphore sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jul 17 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >semaphore_sample
+the producer generates a number: 1
+the consumer[0] get a number: 1
+msh >the producer generates a number: 2
+the consumer[1] get a number: 2
+the producer generates a number: 3
+the consumer[2] get a number: 3
+the producer generates a number: 4
+the consumer[3] get a number: 4
+the producer generates a number: 5
+the consumer[4] get a number: 5
+the producer generates a number: 6
+the consumer[0] get a number: 6
+the producer generates a number: 7
+the consumer[1] get a number: 7
+the producer generates a number: 8
+the consumer[2] get a number: 8
+the producer generates a number: 9
+the consumer[3] get a number: 9
+the producer generates a number: 10
+the consumer[4] get a number: 10
+the consumer[0] sum is 55 
+ the consumer[32] exit!
+the producer exit!
+```

+ 142 - 0
semaphore/producer_consumer.c

@@ -0,0 +1,142 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */  
+
+/*
+ * 程序清单:生产者消费者例子
+ *
+ * 这个例子中将创建两个线程用于实现生产者消费者问题
+ */
+#include <rtthread.h>
+
+#define THREAD_PRIORITY       6
+#define THREAD_STACK_SIZE     512
+#define THREAD_TIMESLICE      5
+
+/* 定义最大5个元素能够被产生 */
+#define MAXSEM 5
+
+/* 用于放置生产的整数数组 */
+rt_uint32_t array[MAXSEM];
+
+/* 指向生产者、消费者在array数组中的读写位置 */
+static rt_uint32_t set, get;
+
+/* 指向线程控制块的指针 */
+static rt_thread_t producer_tid = RT_NULL;
+static rt_thread_t consumer_tid = RT_NULL;
+
+struct rt_semaphore sem_lock;
+struct rt_semaphore sem_empty, sem_full;
+
+/* 生产者线程入口 */
+void producer_thread_entry(void *parameter)
+{
+    int cnt = 0;
+
+    /* 运行10次 */
+    while (cnt < 10)
+    {
+        /* 获取一个空位 */
+        rt_sem_take(&sem_empty, RT_WAITING_FOREVER);
+
+        /* 修改array内容,上锁 */
+        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
+        array[set % MAXSEM] = cnt + 1;
+        rt_kprintf("the producer generates a number: %d\n", array[set % MAXSEM]);
+        set++;
+        rt_sem_release(&sem_lock);
+
+        /* 发布一个满位 */
+        rt_sem_release(&sem_full);
+        cnt++;
+
+        /* 暂停一段时间 */
+        rt_thread_mdelay(20);
+    }
+
+    rt_kprintf("the producer exit!\n");
+}
+
+/* 消费者线程入口 */
+void consumer_thread_entry(void *parameter)
+{
+    rt_uint32_t sum = 0;
+
+    while (1)
+    {
+        /* 获取一个满位 */
+        rt_sem_take(&sem_full, RT_WAITING_FOREVER);
+
+        /* 临界区,上锁进行操作 */
+        rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
+        sum += array[get % MAXSEM];
+        rt_kprintf("the consumer[%d] get a number: %d\n", (get % MAXSEM), array[get % MAXSEM]);
+        get++;
+        rt_sem_release(&sem_lock);
+
+        /* 释放一个空位 */
+        rt_sem_release(&sem_empty);
+
+        /* 生产者生产到10个数目,停止,消费者线程相应停止 */
+        if (get == 10) break;
+
+        /* 暂停一小会时间 */
+        rt_thread_mdelay(50);
+    }
+
+    rt_kprintf("the consumer sum is: %d\n", sum);
+    rt_kprintf("the consumer exit!\n");
+}
+
+int producer_consumer(void)
+{
+    set = 0;
+    get = 0;
+
+    /* 初始化3个信号量 */
+    rt_sem_init(&sem_lock, "lock",     1,      RT_IPC_FLAG_FIFO);
+    rt_sem_init(&sem_empty, "empty",   MAXSEM, RT_IPC_FLAG_FIFO);
+    rt_sem_init(&sem_full, "full",     0,      RT_IPC_FLAG_FIFO);
+
+    /* 创建生产者线程 */
+    producer_tid = rt_thread_create("producer",
+                                    producer_thread_entry, RT_NULL,
+                                    THREAD_STACK_SIZE,
+                                    THREAD_PRIORITY - 1, THREAD_TIMESLICE);
+    if (producer_tid != RT_NULL)
+    {
+        rt_thread_startup(producer_tid);
+    }
+    else
+    {
+        rt_kprintf("create thread producer failed");
+        return -1;
+    }
+
+    /* 创建消费者线程 */
+    consumer_tid = rt_thread_create("consumer",
+                                    consumer_thread_entry, RT_NULL,
+                                    THREAD_STACK_SIZE,
+                                    THREAD_PRIORITY + 1, THREAD_TIMESLICE);
+    if (consumer_tid != RT_NULL)
+    {
+        rt_thread_startup(consumer_tid);
+    }
+    else
+    {
+        rt_kprintf("create thread consumer failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(producer_consumer, producer_consumer sample);

+ 112 - 0
semaphore/semaphore_sample.c

@@ -0,0 +1,112 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:信号量例程
+ *
+ * 该例程创建了一个动态信号量,展示了获取信号量超时和获取成功的情况
+ *
+ */
+#include <rtthread.h>
+
+#define THREAD_PRIORITY         25
+#define THREAD_TIMESLICE        5
+
+/* 指向信号量的指针 */
+static rt_sem_t dynamic_sem = RT_NULL;
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread1_stack[1024];
+static struct rt_thread thread1;
+static void rt_thread1_entry(void *parameter)
+{
+    static rt_uint8_t count = 0;
+  
+    while(1)
+    {
+        if(count <= 100)
+        {
+            count++;           
+        }
+        else
+            return; 
+        
+        /* count每计数10次,就释放一次信号量 */
+         if(0 == (count%10))
+        {
+            rt_kprintf("t1 release a dynamic semaphore.\n" ); 
+            rt_sem_release(dynamic_sem);            
+        }
+    }
+}
+
+ALIGN(RT_ALIGN_SIZE)
+static char thread2_stack[1024];
+static struct rt_thread thread2;
+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++;             
+            rt_kprintf("t2 take a dynamic semaphore. number = %d\n" ,number);                        
+        }
+    }   
+}
+
+/* 信号量示例的初始化 */
+int semaphore_sample()
+{
+    /* 创建一个动态信号量,初始值是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");
+    }
+
+    rt_thread_init(&thread1,
+                   "thread1",
+                   rt_thread1_entry,
+                   RT_NULL,
+                   &thread1_stack[0],
+                   sizeof(thread1_stack), 
+                   THREAD_PRIORITY, THREAD_TIMESLICE);
+    rt_thread_startup(&thread1);
+                   
+    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);
+

+ 148 - 0
signal/README.md

@@ -0,0 +1,148 @@
+# 信号 #
+
+信号用来通知线程发生了异步事件,又称为软中断信号,线程之间可以互相发送软中断信号。
+
+## 介绍 ##
+
+这个例子会创建两个线程线程1和线程2,每个线程会分别安装信号,然后给这两个线程发送信号,线程收到信号后会执行对应的信号处理函数。
+
+## 程序清单 ##
+
+```{.c}
+/*
+ * 程序清单:信号例程
+ *
+ * 这个例子会创建两个线程线程1和线程2,每个线程会分别安装信号,然后给这两个线程发送信号。
+ *
+ */
+#include <rtthread.h>
+
+#define THREAD_PRIORITY         25
+#define THREAD_STACK_SIZE       512
+#define THREAD_TIMESLICE        5
+
+/*
+ * 为了在一个线程中访问另一个线程的控制块,所以把线程块指针中访问
+ * 另一个线程的控制块,所以把线程块指针声明成全局类型以供全局访问
+ */
+static rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL;
+
+/* 线程1的信号处理函数 */
+void thread1_signal_handler(int sig)
+{
+    rt_kprintf("thread1 received signal %d\n", sig);
+}
+
+/* 线程2的信号处理函数 */
+void thread2_signal_handler(int sig)
+{
+    rt_kprintf("thread2 received signal %d\n", sig);
+}
+
+/* 线程1的入口函数 */
+static void thread1_entry(void *parameter)
+{
+    int cnt = 0;
+
+    /* 安装信号 */
+    rt_signal_install(SIGUSR1, thread1_signal_handler);
+    rt_signal_unmask(SIGUSR1);
+
+    /* 运行10次 */
+    while (cnt < 10)
+    {
+        /* 线程1采用低优先级运行,一直打印计数值 */
+        rt_kprintf("thread1 count : %d\n", cnt);
+
+        cnt++;
+        rt_thread_delay(10);
+    }
+}
+
+/* 线程2的入口函数 */
+static void thread2_entry(void *parameter)
+{
+    int cnt = 0;
+
+    /* 安装信号 */
+    rt_signal_install(SIGUSR2, thread2_signal_handler);
+    rt_signal_unmask(SIGUSR2);
+
+    /* 运行10次 */
+    while (cnt < 10)
+    {
+        rt_kprintf("thread2 count : %d\n", cnt);
+
+        cnt++;
+        rt_thread_delay(20);
+    }
+}
+
+/* 信号示例的初始化 */
+int signal_sample()
+{
+    /* 创建线程1 */
+    tid1 = rt_thread_create("t1", /* 线程1的名称是t1 */
+                            thread1_entry, RT_NULL,   /* 入口是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", /* 线程2的名称是t2 */
+                            thread2_entry, RT_NULL,   /* 入口是thread2_entry,参数是RT_NULL */
+                            THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE);
+
+    if (tid2 != RT_NULL) /* 如果获得线程控制块,启动这个线程 */
+        rt_thread_startup(tid2);
+
+    rt_thread_delay(50);
+
+    /* 发送信号 SIGUSR1 给线程1 */
+    rt_thread_kill(tid1, SIGUSR1);
+    /* 发送信号 SIGUSR2 给线程2 */
+    rt_thread_kill(tid2, SIGUSR2);
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(signal_sample, signal sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jul 17 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >si 
+signal_sample
+msh >signal_sample
+thread2 count : 0
+thread1 count : 0
+thread1 count : 1
+thread2 count : 1
+thread1 count : 2
+thread1 count : 3
+thread2 count : 2
+thread1 count : 4
+msh >thread2 received signal 11
+thread2 count : 3
+thread1 received signal 10
+thread1 count : 5
+thread1 count : 6
+thread2 count : 4
+thread1 count : 7
+thread1 count : 8
+thread2 count : 5
+thread1 count : 9
+thread2 count : 6
+thread2 count : 7
+thread2 count : 8
+thread2 count : 9
+```
+
+

+ 84 - 0
signal/signal_sample.c

@@ -0,0 +1,84 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:信号例程
+ *
+ * 这个例子会创建一个线程,线程安装信号,然后给这个线程发送信号。
+ *
+ */
+#include <rtthread.h>
+
+#define THREAD_PRIORITY         25
+#define THREAD_STACK_SIZE       512
+#define THREAD_TIMESLICE        5
+
+/*
+ * 为了在一个线程中访问另一个线程的控制块,所以把线程块指针中访问
+ * 另一个线程的控制块,所以把线程块指针声明成全局类型以供全局访问
+ */
+static rt_thread_t tid1 = RT_NULL;
+
+/* 线程1的信号处理函数 */
+void thread1_signal_handler(int sig)
+{
+    rt_kprintf("thread1 received signal %d\n", sig);
+}
+
+/* 线程1的入口函数 */
+static void thread1_entry(void *parameter)
+{
+    int cnt = 0;
+
+    /* 安装信号 */
+    rt_signal_install(SIGUSR1, thread1_signal_handler);
+    rt_signal_unmask(SIGUSR1);
+
+    /* 运行10次 */
+    while (cnt < 10)
+    {
+        /* 线程1采用低优先级运行,一直打印计数值 */
+        rt_kprintf("thread1 count : %d\n", cnt);
+
+        cnt++;
+        rt_thread_mdelay(100);
+    }
+}
+
+/* 信号示例的初始化 */
+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);
+    }
+    else
+    {
+        rt_kprintf("create t1 failed");
+        return -1;
+    }
+
+    rt_thread_mdelay(300);
+
+    /* 发送信号 SIGUSR1 给线程1 */
+    rt_thread_kill(tid1, SIGUSR1);
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(signal_sample, signal sample);

+ 137 - 0
thread/README.md

@@ -0,0 +1,137 @@
+# 创建与删除动态线程 #
+
+## 介绍 ##
+
+程序清单:创建和删除线程例程
+这个例子会创建两个线程,在一个线程中删除另外一个线程。
+
+## 程序清单 ##
+
+```{.c}
+ /*
+ * 程序清单:创建和删除线程
+ *
+ * 这个例子会创建两个线程,在一个线程中删除另外一个线程。
+ */
+#include <rtthread.h>
+
+#define THREAD_PRIORITY     25
+#define THREAD_STACK_SIZE   512
+#define THREAD_TIMESLICE    5
+
+/*
+ * 线程删除(rt_thread_delete)函数仅适合于动态线程,为了在一个线程
+ * 中访问另一个线程的控制块,所以把线程块指针声明成全局类型以供全
+ * 局访问
+ */
+static rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL;
+/* 线程1的入口函数 */
+static void thread1_entry(void *parameter)
+{
+    rt_uint32_t count = 0;
+
+    while (1)
+    {
+        /* 线程1采用低优先级运行,一直打印计数值 */
+        rt_kprintf("thread count: %d\n", count ++);
+    }
+}
+
+static void thread1_cleanup(struct rt_thread *tid)
+{
+    if (tid != tid1)
+    {
+        return ;
+    }
+    rt_kprintf("thread1 end\n");
+    tid1 = RT_NULL;
+}
+
+/* 线程2的入口函数 */
+static void thread2_entry(void *parameter)
+{
+    /* 线程2拥有较高的优先级,以抢占线程1而获得执行 */
+
+    /* 线程2启动后先睡眠10个OS Tick */
+    rt_thread_delay(10);
+
+    /*
+     * 线程2唤醒后直接删除线程1,删除线程1后,线程1自动脱离就绪线程
+     * 队列
+     */
+    rt_thread_delete(tid1);
+
+    /*
+     * 线程2继续休眠10个OS Tick然后退出,线程2休眠后应切换到idle线程
+     * idle线程将执行真正的线程1控制块和线程栈的删除
+     */
+    rt_thread_delay(10);
+}
+
+static void thread2_cleanup(struct rt_thread *tid)
+{
+    /*
+     * 线程2运行结束后也将自动被删除(线程控制块和线程栈在idle线
+     * 程中释放)
+     */
+
+    if (tid != tid2)
+    {
+        return ;
+    }
+    rt_kprintf("thread2 end\n");
+    tid2 = RT_NULL;
+}
+
+/* 线程示例的初始化 */
+int thread_sample()
+{
+    rt_thread_t init_thread;
+
+    rt_err_t result;
+    /* 创建线程1 */
+    tid1 = rt_thread_create("t1", /* 线程1的名称是t1 */
+                            thread1_entry, RT_NULL,   /* 入口是thread1_entry,参数是RT_NULL */
+                            THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (tid1 != RT_NULL) /* 如果获得线程控制块,启动这个线程 */
+    {
+        tid1->cleanup = thread1_cleanup;
+        rt_thread_startup(tid1);
+    }
+
+    /* 创建线程1 */
+    tid2 = rt_thread_create("t2", /* 线程1的名称是t2 */
+                            thread2_entry, RT_NULL,   /* 入口是thread2_entry,参数是RT_NULL */
+                            THREAD_STACK_SIZE, THREAD_PRIORITY - 1, THREAD_TIMESLICE);
+    if (tid2 != RT_NULL) /* 如果获得线程控制块,启动这个线程 */
+    {
+        tid2->cleanup = thread2_cleanup;
+        rt_thread_startup(tid2);
+    }
+
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(thread_sample, run thread sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jul 17 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >th
+thread_sample
+msh >thread_sample
+msh >thread count: 0
+thread count: 1
+thread count: 2
+...
+thread count: 62
+threathread1 end
+thread2 end
+```
+线程1计数到一定值之后被线程2删除,计数停止,线程2运行完毕自动被删除。

+ 91 - 0
thread/thread_sample.c

@@ -0,0 +1,91 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+ * 程序清单:创建/删除动态线程
+ *
+ * 这个例子会创建两个线程,一个动态线程,一个静态线程。
+ * 一个线程在运行完毕后自动被系统删除,另一个线程一直打印计数。
+ */
+#include <rtthread.h>
+
+#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);
+    }
+}
+
+ALIGN(RT_ALIGN_SIZE)
+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运行结束后也将自动被系统删除
+    (线程控制块和线程栈依然在idle线程中释放) */
+}
+
+/* 删除线程示例的初始化 */
+int thread_sample(void)
+{
+    /* 创建线程1,名称是t1,入口是thread1_entry*/
+    tid1 = rt_thread_create("t1",
+                            thread1_entry, RT_NULL,
+                            THREAD_STACK_SIZE,
+                            THREAD_PRIORITY, THREAD_TIMESLICE);
+    
+    /* 如果获得线程控制块,启动这个线程 */
+    if (tid1 != RT_NULL)
+    {
+        rt_thread_startup(tid1);
+    }
+    else
+    {
+        rt_kprintf("create t1 failed");
+        return -1;
+    }
+
+    /* 初始化线程2,名称是thread2,入口是thread2_entry */
+    rt_thread_init(&thread2,
+                   "thread2",
+                   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(thread_sample, thread sample);

+ 95 - 0
timer/README.md

@@ -0,0 +1,95 @@
+# 定时器的使用 #
+
+## 介绍 ##
+
+这个例程会创建两个动态定时器对象,一个是单次定时,一个是周期性的定时。
+
+## 程序清单 ##
+
+```{.c}
+/*
+* 程序清单:定时器例程
+*
+* 这个例程会创建两个动态定时器对象,一个是单次定时,一个是周期性的定时
+* */
+#include <rtthread.h>
+
+/* 定时器的控制块 */
+static rt_timer_t timer1;
+static rt_timer_t timer2;
+static int cnt = 0;
+
+/* 定时器1超时函数 */
+static void timeout1(void *parameter)
+{
+    rt_tick_t timeout = 300;
+
+    rt_kprintf("periodic timer is timeout\n");
+
+    /* 运行10次 */
+    if (cnt++ >= 10)
+    {
+        rt_timer_control(timer1, RT_TIMER_CTRL_SET_ONESHOT, (void *)&timeout);
+    }
+}
+
+/* 定时器2超时函数 */
+static void timeout2(void *parameter)
+{
+    rt_kprintf("one shot timer is timeout\n");
+}
+
+int timer_sample(void)
+{
+    /* 创建定时器1 */
+    timer1 = rt_timer_create("timer1", /* 定时器名字是 timer1 */
+                             timeout1, /* 超时时回调的处理函数 */
+                             RT_NULL, /* 超时函数的入口参数 */
+                             10, /* 定时长度,以OS Tick为单位,即10个OS Tick */
+                             RT_TIMER_FLAG_PERIODIC); /* 周期性定时器 */
+
+    /* 启动定时器 */
+    if (timer1 != RT_NULL) rt_timer_start(timer1);
+
+    /* 创建定时器2 */
+    timer2 = rt_timer_create("timer2", /* 定时器名字是 timer2 */
+                             timeout2, /* 超时时回调的处理函数 */
+                             RT_NULL, /* 超时函数的入口参数 */
+                             30, /* 定时长度为30个OS Tick */
+                             RT_TIMER_FLAG_ONE_SHOT); /* 单次定时器 */
+
+    /* 启动定时器 */
+    if (timer2 != RT_NULL) rt_timer_start(timer2);
+    return 0;
+}
+/* 如果设置了RT_SAMPLES_AUTORUN,则加入到初始化线程中自动运行 */
+#if defined (RT_SAMPLES_AUTORUN) && defined(RT_USING_COMPONENTS)
+    INIT_APP_EXPORT(timer_sample);
+#endif
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(timer_sample, timer sample);
+```
+
+## 运行结果 ##
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.0.4 build Jun 14 2018
+ 2006 - 2018 Copyright by rt-thread team
+msh >timer
+timer_static_sample
+msh >timer_static_sample
+msh >periodic timer is timeout
+periodic timer is timeout
+one shot timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+periodic timer is timeout
+```

+ 63 - 0
timer/timer_sample.c

@@ -0,0 +1,63 @@
+/* 
+ * Copyright (c) 2006-2018, RT-Thread Development Team 
+ * 
+ * SPDX-License-Identifier: Apache-2.0 
+ * 
+ * Change Logs: 
+ * Date           Author       Notes 
+ * 2018-08-24     yangjie      the first version 
+ */ 
+
+/*
+* 程序清单:定时器例程
+*
+* 这个例程会创建两个动态定时器,一个是单次定时,一个是周期性定时
+*/
+#include <rtthread.h>
+
+/* 定时器的控制块 */
+static rt_timer_t timer1;
+static rt_timer_t timer2;
+static int cnt = 0;
+
+/* 定时器1超时函数 */
+static void timeout1(void *parameter)
+{
+    rt_kprintf("periodic timer is timeout %d\n", cnt);
+
+    /* 运行第10次,停止周期定时器 */
+    if (cnt++ >= 9)
+    {
+        rt_timer_stop(timer1);
+        rt_kprintf("periodic timer was stopped! \n");
+    }
+}
+
+/* 定时器2超时函数 */
+static void timeout2(void *parameter)
+{
+    rt_kprintf("one shot timer is timeout\n");
+}
+
+int timer_sample(void)
+{
+    /* 创建定时器1  周期定时器 */
+    timer1 = rt_timer_create("timer1", timeout1,
+                             RT_NULL, 10,
+                             RT_TIMER_FLAG_PERIODIC);
+
+    /* 启动定时器1 */
+    if (timer1 != RT_NULL) rt_timer_start(timer1);
+
+    /* 创建定时器2 单次定时器 */
+    timer2 = rt_timer_create("timer2", timeout2,
+                             RT_NULL,  30,
+                             RT_TIMER_FLAG_ONE_SHOT);
+
+    /* 启动定时器2 */
+    if (timer2 != RT_NULL) rt_timer_start(timer2);
+    return 0;
+}
+
+/* 导出到 msh 命令列表中 */
+MSH_CMD_EXPORT(timer_sample, timer sample);