rtthread系统 - 普中stm32开发板 - rtthread内核资源 - 线程

7 篇文章 2 订阅
7 篇文章 0 订阅

介绍

在FreeRTOS、UCOS操作系统里面叫任务,在RT-Thread里面叫线程,其实都是一个意思,都是假想这个线程(任务)独占CPU。而在RT-Thread的线程里面,除了有像FreeRTOS、UCOS那种静态创建任务,还有可以动态创建,动态创建就提供了很大便利。

线程调度

RT-Thread中提供的线程调度器是基于优先级的全抢占式调度:在系统中除了中断处理函数、调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身。优先级从0~255(也可以配置成8个或者32个优先级),值越小优先级越高,最小的优先级分配给空闲线程。系统总是运行着就绪的最高优先级的任务,即使正在运行着低优先级也会抢占过去。同等优先级的,就按照原先设定的时间进行轮询式运行。

线程状态

因为线程是假象自己拥有着CPU使用权,但是同一时刻内只有一个线程正在运行,那么不在运行的线程,就会处于其他状态。

状态描述
RT_THREAD_INIT线程初始状态。当线程刚开始创建还没开始运行时就处于这个状态;在这个状态下,线程不参与调度
RT_THREAD_SUSPEND挂起态、阻塞态。线程此时被挂起:它可能因为资源不可用而挂起等待;或线程主动延时一段时间而被挂起。在这个状态下,线程不参与调度
RT_THREAD_READY就绪态。线程正在运行;或当前线程运行完让出处理器后,操作系统寻找最高优先级的就绪态线程运行
RT_THREAD_RUNNING运行态。线程当前正在运行,在单核系统中,只有rt_thread_self()函数返回的线程处于这个状态;在多核系统中则不受这个限制。
RT_THREAD_CLOSE线程结束态。当线程运行结束时将处于这个状态。这个状态的线程不参与线程的调度。
RT_THREAD_INIT线程初始状态。当线程刚开始创建还没开始运行时就处于这个状态;在这个状态下,线程不参与调度

线程状态转换如图
在这里插入图片描述

线程创建和删除

main.c文件目录下创建一个单独的文件(不影响其他文件),这个文件用于创建启动之后关于内核相关资源的测试。
函数原型

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)
rt_err_t rt_thread_delete(rt_thread_t thread)

启动测试

#include <rtthread.h>

void create_th(void *para)
{
    rt_kprintf("create entry!\r\n");
}

int init_func(void)
{
    rt_thread_t t_thread;

    t_thread = rt_thread_create(
        "create",       // name the name of thread, which shall be unique
        create_th,      // entry the entry function of thread,
        NULL,           // parameter the parameter of thread enter function
        1024,           // stack_size the size of thread stack
        12,             // priority the priority of thread
        5               // tick the time slice if there are same priority thread
    );
    rt_thread_startup(t_thread);

    return RT_EOK;
}
INIT_APP_EXPORT(init_func);

这里init_func函数创建了一个线程,并且INIT_APP_EXPORT宏将这个函数在内核初始化时候就执行这个函数(这一点,在使用上带来了一定的便利),线程创建好并不会立刻运行,而是会进入初始化好的状态,需要调用rt_thread_startup函数来启动线程,启动之后才会从线程入口开始执行,如果没有假如循环,线程函数执行完就会自动删除了。
创建一个线程,并立刻启动

rt_thread_startup(rt_thread_create("thread1", thread_entry, NULL, 256, 25, 5));

在线程里面,运行四次后删除

void thread_entry(void* parameter)
{
    rt_uint32_t count = 0;

    while (1)
    {
        /* 打印线程计数值输出 */
        rt_kprintf("thread count: %d\n", count++);

        /* 运行4次后删除 */
        if (count > 4)
        {
            rt_thread_delete(rt_thread_self());
        }

        rt_thread_mdelay(1000);
    }
}

但是这种情况会出现一个错误

(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer) assertion failed at function:rt_timer_control, line number:463

在线程删除的时候就抛出了这个错误,原因是线程里面不能使用rt_thread_delete函数来删除自身,如果想删除自身,就让程序跳出死循环走出线程入口函数,系统就会自动回收这个线程了。
针对rt_thread_delete函数,一般只能由其他线程调用或在定时器超时函数中调用。

2.1.4 线程初始化和脱离

线程的初始化和创建线程类似,功能都是生成可运行的线程,但是初始话与创建不太一样,顾名思义,“创建”是由无到有,“初始化”是将有的变成初始化样子。创建线程就是动态的分配内存去维护线程,而初始化线程就不太一样,除了要事先静态定义好线程(并不是句柄,注意区分),还要分配好线程运行时所需要的栈空间。
线程脱离也是和删除线程类似,是针对由通过初始化的线程进行从内核中脱离。
函数原型

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)
rt_err_t rt_thread_detach(rt_thread_t thread)

线程控制块相关定义

#define THREAD_STACK_SIZE       256
#define THREAD_PRIORITY         25
#define THREAD_TIMESLICE        5

初始化

/* 初始化线程2 */
    result = rt_thread_init(
                &thread2, "thread2",                        /* 线程名:t2 */
                thread_entry, (void*)2,                     /* 线程的入口是thread_entry,入口参数是2 */
                &thread2_stack[0], sizeof(thread2_stack),   /* 线程栈是thread2_stack */
                THREAD_PRIORITY + 1, 10);
    if (result == RT_EOK)                                   /* 如果返回正确,启动线程2 */
    {
        rt_thread_startup(&thread2);
    }

脱离

rt_thread_detach(&thread2);

线程挂起和恢复

可以主动使用“rt_thread_suspend”函数进行挂起,但要立刻使用“rt_schedule”函数来切换一次。主动挂起后,认为线程在某一时刻不再执行,直到恢复。
函数原型

rt_err_t rt_thread_suspend(rt_thread_t thread)
rt_err_t rt_thread_resume(rt_thread_t thread)

创建一个新线程,挂起后运行4s重新恢复。

/* 创建线程3 */
    thread3 = rt_thread_create("thread3", thread_entry, (void *)3, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
    if (thread3 != RT_NULL)
    {
        rt_thread_startup(thread3);
    }
    rt_thread_suspend(thread3);
    rt_thread_mdelay(4000);
    rt_thread_resume(thread3);

结尾

rtthread学习中,打开主页查看更多笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值