创建线程Creating Threads

一旦RTOS开始运行,就会有很多系统调用来管理和控制活跃的线程。默认情况下,main()函数自动被创建为第一个可运行的线程。在第一个例子里我们使用main()函数创建了其他线程,并且随后让main()结束运行。然而我们还可以让main当成一个真正的thread使用。首先,我们需要获取它的ID号。此时,我们第一个要调用的RTOS函数就是osThreadGetId(),这个函数返回当前运行thread的ID号,并把它存在ID句柄里。当我们未来某一时刻在OS调用中需要这个线程时,我们使用的就是这个线程的句柄,而非线程的函数名。

  1.  osThreadId main_id;//创建线程句柄
  2.  void main(void)
  3.  {
  4.  /*获取main线程的ID号*/
  5.  main_id = osThreadGetId();
  6.  while(1)
  7.  {}
  8.  }

现在我们有了main的ID句柄,就可以创建其他应用线程,并随后调用osTermainate(main_id)来结束main线程。相比让一个线程运行到最后一个花括号来结束,这种结束方法更好一些。当然,我们还可以添加while(1)这个循环来继续使用main函数。

在第一个例子中我们就看到main线程可以作为一个launcher 线程来创建其他应用线程。仅需要两步就行:第一步,定义线程结构体(同时还可以定义线程传递参数)。

  1.  osThreadId thread_id; //线程句柄
  2.  void thread1(void const *argument); //thread1的函数原型
  3.  osThreadDef(thread1, osPriorityNormal, 1, 0); //线程定义结构体

定义线程结构体需要先定义线程函数名、线程优先级、创建线程的实例化个数和它的栈大小。这些参数后续会详细说明。一旦定义了线程结构体,我们就可以用osThreadCreated() API来创建线程。线程经常在main线程里创建,当然也可以在其他地方。

thread1_id = osThreadCreated(osThread(thread1), NULL);

上面这条代码创建线程并启动它运行。另外,在启动线程时可以给它传递个参数。

  1.  uint32_t startupParameter = 0x23;
  2.  thread1_id = osThreadCreate(osThread(thread1), startupParameter);

当创建线程时,还将给它分配一个栈,用来存储上下文切换的数据。注意不要和Cortex处理器栈混淆,它只是分配给线程的一段存储空间。在RTOS配置文件里已经定义了一个默认的栈大小,当然我们也可以自定义栈的大小。osThreadDef()这个函数的最后一个参数设为0时表示使用默认栈大小。如果需要的话,也可以通过在线程结构体里定义一个更大的栈来增加额外的存储资源。

  1. osThreadDef(thread1, osPriorityNomal, 1, 0); //分配默认栈大小 
  2. osThreadDef(thread2, osPriorityNomal, 1, 1024); //分配1kB的栈大小

当然,如果你分配了更大的栈空间,在RTOS配置文件里就需要增加额外的存储空间。

线程的管理和优先级Thread Management and Priority

在创建线程的时候就会给它分配一个优先级。RTOS的调度器靠线程的优先级来决定要调度哪个线程运行。假如同时有几个线程都准备运行,优先级最高的线程就会进入运行状态。如果一个高优先级线程处于准备运行状态,它就会抢占正在运行的低优先级线程。有一点非常重要,高优先级线程占用CPU运行的时候永远不会停止,除非有RTOS API调用来阻塞它,或者有更高优先级的线程来抢占它。线程的优先级在线程结构体中定义,下面列出可用的优先级定义,其中一般默认的优先级是osPriorityNormal。

CMSIS-RTOS Priority Levels
osPriorityIdle
osPriorityLow
osPriorityBelowNormal
osPriorityNormal
osPriorityAboveNormal
osPriorityHigh
osPriorityRealTime
osPriorityError

一旦线程开始运行,我们就可以使用几个OS系统调用来管理线程。当然也可以通过其他函数或在它自己代码里面提升或者降低它的优先级。

osStatus osThreadSetPriority(threadID, priority);
osPriority osThreadGetPriority(threadID);

在创建线程之后,也可以通过它自己或者其他活跃的线程来删除它。再强调一次,我们使用thread ID而不是它的函数名来操作。

osStatus = osThreadTermainate(threadID1);

另外,同优先级线程间的切换有一种特殊情况,就是使用协作(co-operative)切换方式:

osStatus osThreadYield();//切换到另外一个准备运行的线程

多重实例化Multiple Instances

RTOS的一个有趣功能就是可以针对一个线程进行多个实例化,例如你可以基于一个线程代码创建多个用于控制UART的实例,此时,每个UART的实例都会管理一个不同的UART硬件。

首先我们要创建线程结构体,并设置线程实例个数为2:

osThreadDef(thread1, osPriorityNormal, 2, 0);

空闲线程Idle Demon

CMSIS-RTOS提供的最后一个定时器服务函数并不是一个真正的定时器,但是这里是最合适讨论它的地方。如果在我们的RTOS程序里没有任何线程正在运行,或者准备运行(举个例子,所有的线程都处于等待延时函数中),那么RTOS就会利用空闲的运行时间调用一个“Idle Demon”的线程,这个函数同样位于RTX_Conf_CM.c文件里面,空闲线程拥有一个低优先级,只有在没有其他任何线程准备运行的情况下才会运行。

void os_idle_demon(void)
{
for(;;){
/*此处包含一些用户的的可选代码,在没有线程运行时执行*/
}
}

你可以在这个线程里加入任何代码,但是同样要遵守常规线程的基本准则,一个最简单的应用就是在此线程中添加控制器MCU的低功耗模式。

void os_idle_demon(void)
{
__wfe();
}

下一步什么情况取决于MCU的功耗模式选择,至少CPU会暂停,直到sysTick产生中断并继续执行调度器。如果有线程准备运行,CPU就会去执行这个线程,否则,就会重新进入空闲线程,系统也会重新进入睡眠状态。

线程间通信 Inter-Thread Communication

前面我们已经学习了如何把你的应用代码设计成独立的线程,以及如何访问RTOS的时间服务函数。在实际的工程应用中,线程间的通信是必不可少的,任何一个RTOS都会支持几种通信方式来连接各种不同的线程。CMSIS-RTOS API支持的通信方式有:信号(signals),信号量(semaphores),互斥锁(mutexes),邮箱(mailboxes)和消息队列(message queues)。所有这些首要的核心概念就是并发性。在这一章,将集中讨论多任务间的同步问题。

信号 Signals

CMSIS RTOS RTX支持单线程16种信号标志,这些信号存储在线程控制块里,一个线程会暂停执行,直到一个或一组信号标志被其他线程置位。

每个线程有16个信号标志,一个线程可能被置于等待状态,直到一种模式的信号被其他线程置位。然后此线程就会返回等待状态,并等待调度器调度到运行状态。

调用信号等待后,系统会挂起正在运行的线程,并把它置于等待事件(wait_event)状态,直到所有的信号标志被置位,线程才会恢复运行。当然也可以加入超时机制,以便让线程可以顺利返回等待状态。默认初始化超时值是0xFFFF。

osEvent osSignalWait(int32_t signals, uint32_t millisec);

调用osSignalWait之后会把信号复位,如果后面还有信号被置位,线程就可以继续执行,你可以读osEvent.value.signals的值来获取哪个标志被置位。

任何一个线程都可以置位或清除另外一个线程的信号:

int32_t osSinalSet(osThreadId thread_id, int32_t signals);
int32_t osSignalClear(osThreadId thread_id, int32_t signals);

来源:https://blog.csdn.net/ichamber/article/details/53116253

ARM官方《CMSIS-RTOS教程》之线程Threads的更多相关文章

  1. 【转帖】ECLIPSE-JEE-LUNA-SR2官方汉化教程

    ECLIPSE-JEE-LUNA-SR2官方汉化教程 工具/原料 Eclipse-jee-luna-SR2 步骤/方法 1.在浏览器输入网址http://www.eclipse.org/babel/d ...

  2. ActiveReports 报表控件官方中文入门教程 (3)-如何选择页面报表和区域报表

    本篇文章将介绍区域报表和页面报表的常见使用场景.区别和选择报表类型的一些建议,两种报表的模板设计.数据源(设计时和运行时)设置.和浏览报表的区别. ActiveReports 报表控件官方中文入门教程 ...

  3. ActiveReports 报表控件官方中文入门教程 (1)-安装、激活以及产品资源

    本系列文章主要是面向初次接触 ActiveReports 产品的用户,可以帮助您在三天之内轻松的掌握ActiveReports控件的基本使用方法,包括安装.激活.创建报表.绑定数据源以及发布等内容.本 ...

  4. ActiveReports 报表控件官方中文入门教程 (2)-创建、数据源、浏览以及发布

    本篇文章将阐述首次使用 ActiveReports 报表控件 的方法,包括添加报表文件.绑定数据源以及如何发布报表等内容. ActiveReports 报表控件官方中文入门教程 (1)-安装.激活以及 ...

  5. ARM开发软件ADS教程

    ARM开发软件ADS教程 ADS(ARM Developer Suite)是ARM公司推出ARM集成开发环境,操作简单方便,获得广大开发人员的青睐.下面使用ADS v1.2做一个实例教程,帮助大家学会 ...

  6. Spring Boot 与 OAuth2 官方最详细教程

    https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247484357&idx=1&sn=73e501de8591e6 ...

  7. ActiveReports 报表控件官方中文新手教程 (1)-安装、激活以及产品资源

     本系列文章主要是面向初次接触 ActiveReports 产品的用户,能够帮助您在三天之内轻松的掌握ActiveReports控件的基本用法,包含安装.激活.创建报表.绑定数据源以及公布等内容. ...

  8. 微信小程序导航:官方工具+精品教程+DEMO集合(1月7更新)

    1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=14764346784612:简易教程:https://mp.weixin.qq.com/debug ...

  9. CMSIS RTOS -- embOS segger

    #ifndef __CMSIS_OS_H__ #define __CMSIS_OS_H__ #include <stdint.h> #include <stddef.h> #i ...

随机推荐

  1. mysql索引的注意事项

    索引的优点 大大加快数据的查询速度 使用分组和排序进行数据查询时,可以显著减少查询时分组和排序的时间 创建唯一索引,能够保证数据库表中每一行数据的唯一性 在实现数据的参考完整性方面,可以加速表和表之间 ...

  2. 《汇编语言(第三版)》pushf 和 popf 指令,以及标志寄存器在 Debug 中的表示

    pushf 和 popf pushf 的功能是将标志寄存器的值压栈,而 popf 是从栈中弹出数据,输入标志寄存器. pushf 和 popf,为直接访问寄存器提供了方法. 格式 pushf popf ...

  3. 新疆大学OJ(ACM) 1099: 数列有序!

    1099: 数列有序! 时间限制: 1 Sec  内存限制: 128 MB 题目描述 有n(n<=100)个整数,已经按照从小到大顺序排列好,现在另外给一个整数x,请将该数插入到序列中,并使新的 ...

  4. RXjava的简介

    API 介绍和原理简析 1. 概念:扩展的观察者模式 观察者模式面向的需求是:举一个例子,警察在小偷实施作案的时候实施抓捕,在这一个例子中警察是观察者,小偷是被观察者.但是程序的观察者模式和这个还是有 ...

  5. 如何把非服务程序(一般的应用程序)注册为Windows服务

    非服务程序:不是标准的服务形式的程序吧,只是普通的应用程序. 1.要实现这个功能要用到微软提供的两个小工具“instsrv.exe”和“srvany.exe”,工具可以从微软下载安装工具包得到:htt ...

  6. DataTable相关操作,筛选,取前N条数据,去重复行,获取指定列数据

    #region DataTable筛选,排序返回符合条件行组成的新DataTable或直接用DefaultView按条件返回      /// <summary>      /// Dat ...

  7. 用centos镜像 制作本地yum源

    1.上传iso镜像 2.挂载镜像到相应目录 mkdir /yumiso #创建目录mount -t iso9660 /dev/cdrom/sr0 /yumiso #挂载镜像文件到对应目录 3.备份旧的 ...

  8. 2015 Multi-University Training Contest 1 y sequence

    Y sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  9. 洛谷——P1428 小鱼比可爱

    https://www.luogu.org/problem/show?pid=1428 题目描述 人比人,气死人:鱼比鱼,难死鱼.小鱼最近参加了一个“比可爱”比赛,比的是每只鱼的可爱程度.参赛的鱼被从 ...

  10. Qt之QStackedWidget

    简述 QStackedWidget继承自QFrame. QStackedWidget类提供了多页面切换的布局,一次只能看到一个界面. QStackedWidget可用于创建类似于QTabWidget提 ...