物联网嵌入式系统:RT_Thread线程管理学习

0.内存堆和栈的使用

堆(Heap):一般由程序员分配和释放
分配:rt_malloc、rt_calloc、rt_realloc
释放:rt_free
内存初始化:rt_memset

栈(Stack):由编译器自动分配和释放
局部变量、全局变量

1.RT-Thread 的线程介绍

RT-Thread 的线程调度器是抢占式的,主要的工作就是从就绪线程列表中查找最高优先级线程,保证最高优先级的线程能够被运行,最高优先级的任务一旦就绪,总能得到 CPU 的使用权,当一个运行着的线程使一个比它优先级高的线程满足运行条件,当前线程的 CPU 使用权就被剥夺了,或者说被让出了,高优先级的线程立刻得到了 CPU 的使用权。
如果是中断服务程序使一个高优先级的线程满足运行条件,中断完成时,被中断的线程挂起,优先级高的线程开始运行。
当调度器调度线程切换时,先将当前线程上下文保存起来,当再切回到这个线程时,线程调度器将该线程的上下文信息恢复。

这里的上下文指的是:线程执行时候的环境,具体来说:变量、数据、所有寄存器变量、堆变量、栈变量、内存信息等

2.线程的状态

2.1初始状态


当线程刚开始创建还没开始运行时就处于初始状态;在初始状态下,线程不参与调度。此状
态在 RT-Thread 中的宏定义为 RT_THREAD_INIT


2.2就绪状态


在就绪状态下,线程按照优先级排队,等待被执行;一旦当前线程运行完毕让出处理器,操
作系统会马上寻找最高优先级的就绪态线程运行。此状态在 RT-Thread 中的宏定义为
RT_THREAD_READY


2.3运行状态


线程当前正在运行。在单核系统中,只有 rt_thread_self() 函数返回的线程处于运行状态;
在多核系统中,可能就不止这一个线程处于运行状态。此状态在 RT-Thread 中的宏定义为
RT_THREAD_RUNNING


2.4挂起状态


也称阻塞态。它可能因为资源不可用而挂起等待,或线程主动延时一段时间而挂起。在挂起
状态下,线程不参与调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_SUSPEND

 

3.RT_Thread线程管理结构体

/**
 * Thread structure
 */
struct rt_thread
{
    /* rt object */
    char        name[RT_NAME_MAX];                      /**< the name of thread */
    rt_uint8_t  type;                                   /**< type of object */
    rt_uint8_t  flags;                                  /**< thread's flags */

#ifdef RT_USING_MODULE
    void       *module_id;                              /**< id of application module */
#endif

    rt_list_t   list;                                   /**< the object list */
    rt_list_t   tlist;                                  /**< the thread list */

    /* stack point and entry */
    void       *sp;                                     /**< stack point */
    void       *entry;                                  /**< entry */
    void       *parameter;                              /**< parameter */
    void       *stack_addr;                             /**< stack address */
    rt_uint32_t stack_size;                             /**< stack size */

    /* error code */
    rt_err_t    error;                                  /**< error code */

    rt_uint8_t  stat;                                   /**< thread status */

    /* priority */
    rt_uint8_t  current_priority;                       /**< current priority */
    rt_uint8_t  init_priority;                          /**< initialized priority */
#if RT_THREAD_PRIORITY_MAX > 32	 /*RT_Thread默认支持256个优先级,但是STM32平台默认给32个优先等级 */
    rt_uint8_t  number;
    rt_uint8_t  high_mask;
#endif
    rt_uint32_t number_mask;

#if defined(RT_USING_EVENT)
    /* thread event */
    rt_uint32_t event_set;
    rt_uint8_t  event_info;
#endif

#if defined(RT_USING_SIGNALS)
    rt_sigset_t     sig_pending;                        /**< the pending signals */
    rt_sigset_t     sig_mask;                           /**< the mask bits of signal */

    void            *sig_ret;                           /**< the return stack pointer from signal */
    rt_sighandler_t *sig_vectors;                       /**< vectors of signal handler */
    void            *si_list;                           /**< the signal infor list */
#endif

    rt_ubase_t  init_tick;                              /**< thread's initialized tick */
    rt_ubase_t  remaining_tick;                         /**< remaining tick */

    struct rt_timer thread_timer;                       /**< built-in thread timer */

    void (*cleanup)(struct rt_thread *tid);             /**< cleanup function when thread exit */

    /* light weight process if present */
#ifdef RT_USING_LWP
    void        *lwp;
#endif

    rt_uint32_t user_data;                             /**< private user data beyond this thread */
};


typedef struct rt_thread *rt_thread_t;  /*线程句柄指针*/

4.线程创建

4.1动态创建一个线程

1. 不需要创建线程栈的起始地址
2. 线程句柄由系统自动分配

/**
 * This function will create a thread object and allocate thread object memory
 * and stack.
 *
 * @param name the name of thread, which shall be unique 线程名称
 * @param entry the entry function of thread 线程执行方法
 * @param parameter the parameter of thread enter function  线程执行方法参数
 * @param stack_size the size of thread stack  线程栈大小
 * @param priority the priority of thread  线程优先等级
 * @param tick the time slice if there are same priority thread  时间片
 *
 * @return the created thread object  线程句柄
 */
rt_thread_t rt_thread_create(const char *name,
                             void (*entry)(void *parameter),
                             void       *parameter,
                             rt_uint32_t stack_size,
                             rt_uint8_t  priority,
                             rt_uint32_t tick)

4.2静态创建一个线程

1. 需要创建线程栈的起始地址
2. 线程句柄由程序员定义

/**
 * This function will initialize a thread, normally it's used to initialize a
 * static thread object.
 *
 * @param thread the static thread object  线程句柄
 * @param name the name of thread, which shall be unique  线程名称
 * @param entry the entry function of thread  线程执行方法
 * @param parameter the parameter of thread enter function 线程执行方法参数
 * @param stack_start the start address of thread stack  线程栈起始地址
 * @param stack_size the size of thread stack 线程栈大小
 * @param priority the priority of thread 优先等级
 * @param tick the time slice if there are same priority thread 时间片
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_init(struct rt_thread *thread,
                        const char       *name,
                        void (*entry)(void *parameter),
                        void             *parameter,
                        void             *stack_start,
                        rt_uint32_t       stack_size,
                        rt_uint8_t        priority,
                        rt_uint32_t       tick)

5.线程启动

/**
 * This function will start a thread and put it to system ready queue
 *
 * @param thread the thread to be started
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_startup(rt_thread_t thread)

6.释放线程句柄

采用静态方式创建线程这种方式,线程控制块和堆栈占用的内存会放在 RW/ZI 段,这段空间在编译时就已经确定,它不是可以动态分配的,所以不能被释放,而只能使用 rt_thread_detach()函数将该线程控制块从对象管理器中脱离。
使用动态定义方式 rt_thread_create()时, RT-Thread 会动态申请线程控制块和堆栈空间。在编译时,编译器是不会感知到这段空间的,只有在程序运行时, RT-Thread 才会从系统堆中申请分配这段内存空间,当不需要使用该线程时,调用 rt_thread_delete()函数就会将这段申请的内存空间重新释放到内存堆中。

这两种方式各有利弊,静态定义方式会占用 RW/ZI 空间,但是不需要动态分配内存,运行时效率较高,实时性较好。
动态方式不会占用额外的 RW/ZI 空间,占用空间小,但是运行时需要动态分配内存,效率没有静态方式高。

/**
 * This function will detach a thread. The thread object will be removed from
 * thread queue and detached/deleted from system object management.
 *
 * @param thread the thread to be deleted
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_detach(rt_thread_t thread)


/**
 * This function will delete a thread. The thread object will be removed from
 * thread queue and deleted from system object management in the idle thread.
 *
 * @param thread the thread to be deleted
 *
 * @return the operation status, RT_EOK on OK, -RT_ERROR on error
 */
rt_err_t rt_thread_delete(rt_thread_t thread)

7.线程睡眠

线程睡眠的时间:sleep/delay 的传入参数 tick 以 1 个 OS Tick 为单位;mdelay 的传入参数 ms 以 1ms 为单位;

rt_err_t rt_thread_sleep(rt_tick_t tick);
rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_mdelay(rt_int32_t ms);

8.线程让出系统资源

当前线程的时间片用完或者该线程主动要求让出处理器资源时,它将不再占有处理器,调度器会选择相同优先级的下一个线程执行。

rt_err_t rt_thread_yield(void);

9.主动挂起线程

一般不会轻易的主动挂起线程,不推荐这样做。

rt_err_t rt_thread_suspend (rt_thread_t thread);

10.恢复线程

恢复线程就是让挂起的线程重新进入就绪状态,并将线程放入系统的就绪队列中;如果被恢复线程在所有就绪态线程中,位于最高优先级链表的第一位,那么系统将进行线程上下文的切换。

rt_err_t rt_thread_resume (rt_thread_t thread);

11.来自官网的例程:

/* 
 * 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,名称是thread1,入口是thread1_entry*/
    tid1 = rt_thread_create("thread1",
                            thread1_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);
    
    /* 如果获得线程控制块,启动这个线程 */
    if (tid1 != RT_NULL)
        rt_thread_startup(tid1);

    /* 初始化线程2,名称是thread2,入口是thread2_entry */
    rt_thread_init(&thread2,
                   "thread2",
                   thread2_entry,
                   RT_NULL,
                   &thread2_stack[0],
                   sizeof(thread2_stack),
                   THREAD_PRIORITY - 1, THREAD_TIMESLICE);
    rt_thread_startup(&thread2);

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(thread_sample, thread sample);

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值