Просмотр исходного кода

Merge pull request #2 from yangjie11/master

add kernel samples
yqiu 7 лет назад
Родитель
Сommit
2c55536dd1

+ 52 - 0
.gitignore

@@ -0,0 +1,52 @@
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf

+ 202 - 0
LICENSE

@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+

+ 57 - 2
README.md

@@ -1,2 +1,57 @@
-# kernel-sample
-RT-Thread kernel samples
+# kernel samples
+
+## 1、介绍
+
+这个软件包包含了内核相关的使用示例代码。
+
+### 1.1 目录结构
+
+| 名称 | 说明 |
+| ---- | ---- |
+| dynmem | 动态堆内存的使用 |
+| event  | 事件的使用 |
+| idlehook  | 空闲任务钩子的使用 |
+| interrupt | 使用开关中断进行线程间同步 |
+| mailbox | 邮箱的使用 |
+| mempool  | 内存池的使用 |
+| msgq | 消息队列的使用 |
+| mutex  | 互斥量的使用、防止优先级翻转特性 |
+| semaphore | 信号量的使用、生产者消费者模型 |
+| signal  | 信号的使用 |
+| thread | 线程的使用 |
+| timer  | 定时器的使用 |
+
+### 1.2 许可证
+
+kernel samples package 遵循 Apache license v2.0 许可,详见 `LICENSE` 文件。
+
+### 1.3 依赖
+
+依赖系统内核对应的模块。
+
+## 2、如何打开 kernel samples
+
+使用 kernel samples package 需要在 RT-Thread 的 menuconfig 配置菜单中选择它,具体路径如下:
+
+```
+RT-Thread online packages
+    miscellaneous packages --->
+        samples: kernel and components samples --->
+            a kernel_samples package for rt-thread --->
+
+```
+
+然后让 RT-Thread 的包管理器自动更新,或者使用 `pkgs --update` 命令更新包到 BSP 中。
+
+## 3、使用 kernel samples
+
+在打开 kernel samples package 后,当进行 BSP 编译时,选择的软件包相关源代码会被加入到 BSP 工程中进行编译。
+
+## 4、注意事项
+
+暂无。
+
+## 5、联系方式 & 感谢
+
+* 维护:name
+* 主页:https://github.com/RT-Thread-packages/kernel-sample.git

+ 57 - 0
SConscript

@@ -0,0 +1,57 @@
+
+from building import *
+Import('rtconfig')
+
+src   = []
+cwd   = GetCurrentDir()
+group = []
+CPPPATH = []
+
+# add kernel samples.
+if GetDepend('KERNEL_SAMPLES_USING_THREAD'):
+    src += ['thread/*.c']
+    CPPPATH += [cwd + '/thread']
+
+if GetDepend('KERNEL_SAMPLES_USING_SEMAPHORE'):
+    src += Glob('semaphore/*.c')
+    CPPPATH += [cwd + '/semaphore']
+
+if GetDepend('KERNEL_SAMPLES_USING_MUTEX'):
+    src += Glob('mutex/*.c')
+    CPPPATH += [cwd + '/mutex']
+
+if GetDepend('KERNEL_SAMPLES_USING_MAILBOX'):
+    src += Glob('mailbox/*.c')
+    CPPPATH += [cwd + '/mailbox']
+
+if GetDepend('KERNEL_SAMPLES_USING_EVENT'):
+    src += Glob('event/*.c')
+    CPPPATH += [cwd + '/event']
+
+if GetDepend('KERNEL_SAMPLES_USING_MESSAGEQUEUE'):
+    src += Glob('msgq/*.c')
+    CPPPATH += [cwd + '/msgq']
+
+if GetDepend('KERNEL_SAMPLES_USING_TIMER'):
+    src += Glob('timer/*.c')
+    CPPPATH += [cwd + '/timer']
+
+if GetDepend('KERNEL_SAMPLES_USING_HEAP'):
+    src += Glob('dynmem/*.c')
+    CPPPATH += [cwd + '/dynmem']
+
+if GetDepend('KERNEL_SAMPLES_USING_MEMPOOL'):
+    src += Glob('mempool/*.c')
+    CPPPATH += [cwd + '/mempool']
+
+if GetDepend('KERNEL_SAMPLES_USING_IDLEHOOK'):
+    src += Glob('idlehook/*.c')
+    CPPPATH += [cwd + '/idlehook']
+
+if GetDepend('KERNEL_SAMPLES_USING_SIGNAL'):
+    src += Glob('signal/*.c')
+    CPPPATH += [cwd + '/signal']
+
+group = DefineGroup('kernel-samples', src, depend = ['PKG_USING_KERNEL_SAMPLES'], CPPPATH = CPPPATH)
+
+Return('group')

+ 74 - 0
dynmem/dynmem_sample.c

@@ -0,0 +1,74 @@
+/* 
+ * 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);

+ 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);

+ 88 - 0
idlehook/idlehook_sample.c

@@ -0,0 +1,88 @@
+/* 
+ * 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_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);

+ 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);

+ 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);

+ 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>
+
+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);

+ 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;
+            }
+        }
+        /* 延时50ms */
+        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);

+ 102 - 0
mutex/mutex_sample.c

@@ -0,0 +1,102 @@
+/* 
+ * 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也会对2个number分别进行加1操作。使用互斥量保证2个number值保持一致
+ */
+#include <rtthread.h>
+
+#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)
+      {
+          /* 线程1获取到互斥量后,先后对number1、number2进行加1操作,然后释放互斥量 */
+          rt_mutex_take(dynamic_mutex, RT_WAITING_FOREVER);          
+          number1++;
+          rt_thread_mdelay(10);
+          number2++;          
+          rt_mutex_release(dynamic_mutex);
+       }	    
+}
+
+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);

+ 144 - 0
semaphore/producer_consumer.c

@@ -0,0 +1,144 @@
+/* 
+ * 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)生产者线程将cnt值每次加1并循环存入array数组的5个成员内;
+ *(2)消费者线程将生产者中生产的数值打印出来,并累加求和
+ */
+#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 
+ */ 
+
+/*
+ * 程序清单:信号量例程
+ *
+ * 该例程创建了一个动态信号量,初始化两个线程,线程1在count每计数10次时,
+ * 发送一个信号量,线程2在接收信号量后,对number进行加1操作
+ */
+#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);
+

+ 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);

+ 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);

+ 64 - 0
timer/timer_sample.c

@@ -0,0 +1,64 @@
+/* 
+ * 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);