收藏官网首页
查看: 12784|回复: 0

【一起来玩RTOS系列】之RT-Thread 通过调度锁保护代码

321

主题

1054

帖子

4502

积分

论坛元老

Rank: 8Rank: 8

积分
4502
QQ
跳转到指定楼层
楼主
发表于 2017-11-25 13:27:58 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
校园创客福利

调度器锁

同中断锁一样把调度器锁住也能让当前运行的任务不被换出,直到调度器解锁。但和中断锁有一点不相同的是,对调度器上锁,系统依然能响应外部中断,中断服务例程依然能进行相应的响应。所以在使用调度器上锁的方式进行任务同步时,需要考虑好任务访问的临界资源是否会被中断服务例程所修改,如果可能会被修改,那么将不适合采用此种方式进行同步。RT-Thread提供的调度锁操作API为:

  1. void rt_enter_critical(void); /* 进入临界区*/
复制代码

调用这个函数后,调度器将被上锁。在锁住调度器期间,系统依然响应中断,如果中断唤醒了更高优先级的线程,调度器并不会立刻执行它,直到调用解锁调度器函数时才会尝试进行下一次调度。


  1. void rt_exit_critical(void); /* 退出临界区*/
复制代码

当系统退出临界区的时候,系统会计算当前是否有更高优先级的线程就绪,如果有比当前线程更高优先级的线程就绪,将切换到这个高优先级线程中执行;如果无更高优先级线程就绪,将继续执行当前任务。

注: rt_enter_critical/rt_exit_critical可以多次嵌套调用,但每调用一次rt_enter_critical就必须相对应地调用一次rt_exit_critical退出操作,嵌套的最大深度是65535。

使用场合

调度器锁能够方便地使用于一些线程与线程间同步的场合,由于轻型,它不会对系统中断响应造成负担;但它的缺陷也很明显,就是它不能被用于中断与线程间的同步或通知,并且如果执行调度器锁的时间过长,会对系统的实时性造成影响(因为使用了调度器锁后,系统将不再具备优先级的关系,直到它脱离了调度器锁的状态)。

下面在机智云gokit上验证如何通过调度锁保护代码,程序创建2个不同优先级的线程,线程1的优先级比线程2高,低优先级线程会执行一段耗时比较长的代码:
(1)若不启用调度锁,即注释掉rt_enter_critical和rt_exit_critical这2行代码,则会发现线程2会被线程1打断,字符串被修改为gokit demo而不是期望打印的Gokit Demo,说明线程2被线程1打断;
(2)若启用调度锁,即不注释掉rt_enter_critical和rt_exit_critical这2行代码,则会发现线程2打印的是期望的Gokit Demo,说明线程2没有被线程1打断,调度锁起到了保护临界代码的作用;

  1. /**
  2.   ****************************************************
  3.   * File Name          : main.c
  4.   * Description        : Main program body
  5.   ****************************************************
  6.   ** This notice applies to any and all portions of this file
  7.   * that are not between comment pairs USER CODE BEGIN and
  8.   * USER CODE END. Other portions of this file, whether
  9.   * inserted by the user or by software development tools
  10.   * are owned by their respective copyright owners.
  11.   *
  12.   * COPYRIGHT(c) 2017 STMicroelectronics
  13.   *
  14.   * Redistribution and use in source and binary forms, with or without modification,
  15.   * are permitted provided that the following conditions are met:
  16.   *   1. Redistributions of source code must retain the above copyright notice,
  17.   *      this list of conditions and the following disclaimer.
  18.   *   2. Redistributions in binary form must reproduce the above copyright notice,
  19.   *      this list of conditions and the following disclaimer in the documentation
  20.   *      and/or other materials provided with the distribution.
  21.   *   3. Neither the name of STMicroelectronics nor the names of its contributors
  22.   *      may be used to endorse or promote products derived from this software
  23.   *      without specific prior written permission.
  24.   *
  25.   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  26.   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  28.   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  29.   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  31.   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  32.   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  33.   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  34.   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35.   *
  36.   ****************************************************
  37.   */
  38. /* Includes ------------------------------------------------------------------*/
  39. #include "main.h"
  40. #include "STM32f1xx_hal.h"
  41. #include "usart.h"
  42. #include "gpio.h"

  43. /* USER CODE BEGIN Includes */
  44. #include "rtthread.h"
  45. #include "string.h"
  46. /* USER CODE END Includes */

  47. /* Private variables ---------------------------------------------------------*/

  48. /* USER CODE BEGIN PV */
  49. /* Private variables ---------------------------------------------------------*/

  50. /* USER CODE END PV */

  51. /* Private function prototypes -----------------------------------------------*/
  52. void SystemClock_Config(void);

  53. /* USER CODE BEGIN PFP */
  54. /* Private function prototypes -----------------------------------------------*/

  55. /* USER CODE END PFP */

  56. /* USER CODE BEGIN 0 */
  57. //重映射串口1到rt_kprintf
  58. void rt_hw_console_output(const char *str)
  59. {
  60.     /* empty console output */
  61.         char aa='\r';
  62.           rt_enter_critical();

  63.                 while(*str!='\0')
  64.                 {
  65.                         if(*str=='\n')
  66.                         {
  67.                                 HAL_UART_Transmit(&huart1, (uint8_t *)&aa, 1, 10);
  68.                         }
  69.                                 HAL_UART_Transmit(&huart1, (uint8_t *)(str++), 1, 10);
  70.                 }
  71.                
  72.                 rt_exit_critical();
  73. }

  74. void rt_hw_us_delay(int us)
  75. {
  76.     rt_uint32_t delta;

  77.     /* 获得延时经过的tick数 */
  78.     us = us * (SysTick->LOAD/(1000000/RT_TICK_PER_SECOND));

  79.     /* 获得当前时间 */
  80.     delta = SysTick->VAL;

  81.     /* 循环获得当前时间,直到达到指定的时间后退出循环 */
  82.     while (delta - SysTick->VAL< us);
  83. }

  84. void rt_hw_ms_delay(int ms)
  85. {
  86.         int i=0,j=0;
  87. for(j=0;j<ms;j++)
  88.         {
  89.         for (i=0;i<2;i++)
  90.         rt_hw_us_delay(500);
  91.         }
  92. }

  93. /*
  94. * 程序清单:通过调度锁保护临界区代码
  95. *线程1的优先级比线程2高,低优先级线程会执行一段耗时比较长的代码;
  96. *(1)若不启用调度锁,即注释掉rt_enter_critical和rt_exit_critical这2行代码,
  97. *则会发现线程2会被线程1打断,字符串被修改为gokit demo而不是期望打印的Gokit Demo,说明线程2被线程1打断;
  98. *(2)若启用调度锁,即不注释掉rt_enter_critical和rt_exit_critical这2行代码,
  99. *则会发现线程2打印的是期望的Gokit Demo,说明线程2没有被线程1打断,调度锁起到了保护临界代码的作用;
  100. */

  101. /* 指向线程控制块的指针 */
  102. static rt_thread_t tid1 = RT_NULL;
  103. static rt_thread_t tid2 = RT_NULL;

  104. char str[]="GOKIT DEMO";

  105. /* 线程1入口 */
  106. static void thread1_entry(void* parameter)
  107. {   
  108. /* 高优先级线程1开始运行,会修改str内容 */
  109.         while(1)
  110.         {
  111.                 strcpy(str,"gokit demo");
  112.                 rt_kprintf("thread1: %s\n",str);
  113.                 rt_thread_delay(1000);
  114.         }
  115. }

  116. /* 线程2入口 */
  117. static void thread2_entry(void* parameter)
  118. {
  119.                 /* 调度器上锁,上锁后,将不再切换到其他线程,仅响应中断 */
  120.                 rt_enter_critical();
  121.                 strcpy(str,"Gokit Demo");
  122.                 /*低优先级线程2执行耗时有点长的代码*/
  123.                 rt_hw_ms_delay(4000);
  124.                 rt_kprintf("thread2: %s\n",str);
  125.           /* 调度器解锁 */
  126.     rt_exit_critical();
  127. }

  128. /* USER CODE END 0 */

  129. int main(void)
  130. {

  131.   /* USER CODE BEGIN 1 */

  132.   /* USER CODE END 1 */

  133.   /* MCU Configuration----------------------------------------------------------*/

  134. //  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  135. //  HAL_Init();

  136. //  /* USER CODE BEGIN Init */

  137. //  /* USER CODE END Init */

  138. //  /* Configure the system clock */
  139. //  SystemClock_Config();

  140. //  /* USER CODE BEGIN SysInit */

  141. //  /* USER CODE END SysInit */

  142. //  /* Initialize all configured peripherals */
  143. //  MX_GPIO_Init();
  144. //  MX_USART1_UART_Init();

  145.   /* USER CODE BEGIN 2 */
  146.        
  147.    /* 创建线程1 */
  148.     tid1 = rt_thread_create("t1",
  149.                                                         thread1_entry,
  150.                                                         RT_NULL,
  151.                                                         512,
  152.                                                         2,
  153.                                                         20);
  154.         if (tid1 != RT_NULL)
  155.                 rt_thread_startup(tid1);
  156.        
  157.         /* 创建线程2 */
  158.         tid2 = rt_thread_create("t2",
  159.                                                         thread2_entry,
  160.                                                         RT_NULL,
  161.                                                         512,
  162.                                                         3,
  163.                                                         20);

  164.         if (tid2 != RT_NULL)
  165.                 rt_thread_startup(tid2);
  166.        
  167.         printf("\r\n机智云  只为智能硬件而生\r\n");
  168.         printf("Gizwits Smart Cloud for Smart Products\r\n");
  169.         printf("链接|增值|开放|中立|安全|自有|自由|生态\r\n");
  170.         printf("www.gizwits.com\r\n");
  171.         printf("\r\nGokit RT-Thread Demo\r\n\r\n");
  172.        
  173.         return 0;
  174.        
  175.        


  176.   /* USER CODE END 2 */

  177.   /* Infinite loop */
  178.   /* USER CODE BEGIN WHILE */
  179. //  while (1)
  180. //  {
  181.   /* USER CODE END WHILE */

  182.   /* USER CODE BEGIN 3 */
  183. //               
  184. //  }
  185.   /* USER CODE END 3 */

  186. }

  187. /** System Clock Configuration
  188. */
  189. void SystemClock_Config(void)
  190. {

  191.   RCC_OscInitTypeDef RCC_OscInitStruct;
  192.   RCC_ClkInitTypeDef RCC_ClkInitStruct;

  193.     /**Initializes the CPU, AHB and APB busses clocks
  194.     */
  195.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  196.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  197.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  198.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  199.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  200.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  201.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  202.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  203.   {
  204.     _Error_Handler(__FILE__, __LINE__);
  205.   }

  206.     /**Initializes the CPU, AHB and APB busses clocks
  207.     */
  208.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  209.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  210.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  211.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  212.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  213.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  214.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  215.   {
  216.     _Error_Handler(__FILE__, __LINE__);
  217.   }

  218.     /**Configure the Systick interrupt time
  219.     */
  220.   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  221.     /**Configure the Systick
  222.     */
  223.   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  224.   /* SysTick_IRQn interrupt configuration */
  225.   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
  226. }

  227. /* USER CODE BEGIN 4 */

  228. /* USER CODE END 4 */

  229. /**
  230.   * @brief  This function is executed in case of error occurrence.
  231.   * @param  None
  232.   * @retval None
  233.   */
  234. void _Error_Handler(char * file, int line)
  235. {
  236.   /* USER CODE BEGIN Error_Handler_Debug */
  237.   /* User can add his own implementation to report the HAL error return state */
  238.   while(1)
  239.   {
  240.   }
  241.   /* USER CODE END Error_Handler_Debug */
  242. }

  243. #ifdef USE_FULL_ASSERT

  244. /**
  245.    * @brief Reports the name of the source file and the source line number
  246.    * where the assert_param error has occurred.
  247.    * @param file: pointer to the source file name
  248.    * @param line: assert_param error line source number
  249.    * @retval None
  250.    */
  251. void assert_failed(uint8_t* file, uint32_t line)
  252. {
  253.   /* USER CODE BEGIN 6 */
  254.   /* User can add his own implementation to report the file name and line number,
  255.     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  256.   /* USER CODE END 6 */

  257. }

  258. #endif

  259. /**
  260.   * @}
  261.   */

  262. /**
  263.   * @}
  264. */

  265. /**************** (C) COPYRIGHT STMicroelectronics ****END OF FILE***/
复制代码



源码下载:
Gokit_RT-Thread.zip (8.7 MB, 下载次数: 2, 售价: 1 金钱)

1、机智云QQ群:G1群:104975951 G2群:491509598 G3群:287087942
机智云爱好者-APP开发群: 599735135
QQ群目前非常活跃,欢迎大家参与进来,交流,讨论,答疑,解惑~~
2、机智云微信公众号: 机智云 gizwits、 机智云智能宠物屋go-iot
关注机智云Gizwits官方公众号随时掌握最新资讯和活动信息
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

加入Q群 返回顶部

版权与免责声明 © 2006-2024 Gizwits IoT Technology Co., Ltd. ( 粤ICP备11090211号 )

快速回复 返回顶部 返回列表