RT-Thread内核之线程调度(三)

4.RT-Thread中的线程?

/**

* 线程结构

*/

struct rt_thread {

/** Object对象 */

char        name[RT_NAME_MAX];                      /**<
线程的名字 */

rt_uint8_t  type;                                   /**< 对象的类型 */

rt_uint8_t  flags;                                  /**< 线程的标志 */

#ifdef RT_USING_MODULE

void       *module_id;                              /**< 应用模块的ID */

#endif

rt_list_t   list;                                   /**< 对象链表 */

rt_list_t   tlist;                                  /**< 线程链表 */

void       *sp;                                     /**< 栈顶指针 */

void       *entry;                                  /**< 入口函数 */

void       *parameter;                              /**< 附加參数 */

void       *stack_addr;                             /**< 栈底地址 */

rt_uint16_t stack_size;                             /**< 线程栈的大小 */

rt_err_t    error;                                  /**< 线程执行的错误码 */

rt_uint8_t  stat;                                   /**< 线程的状态 */

rt_uint8_t  current_priority;                       /**< 线程的当前优先级 */

rt_uint8_t  init_priority;                          /**< 线程的初始优先级 */

#if RT_THREAD_PRIORITY_MAX > 32

rt_uint8_t  number;         /**< 线程优先级相应的组号: current_priority >> 3 */

rt_uint8_t  high_mask;      /**< 线程位号掩码: (1 << 位号) 位号: (current_priority & 7) */

#endif

rt_uint32_t number_mask;    /**< 组号掩码: (1 << 组号) */

#if defined(RT_USING_EVENT)

rt_uint32_t event_set;      /** 线程的事件集 */

rt_uint8_t  event_info;     /** 多事件的逻辑关系: 与/或/非 */

#endif

rt_ubase_t  init_tick;                              /**< 线程初始化的执行滴答值 */

rt_ubase_t  remaining_tick;                         /**< 线程执行的剩余滴答数 */

struct rt_timer thread_timer;                       /**<
内嵌的线程定时器 */

void (*cleanup)(struct rt_thread *tid);             /**< 线程退出时的清除函数 */

rt_uint32_t user_data;                              /**< 私实用户数据 */

};

总的来看。线程皆有由几类成员组成:object,栈相关信息。优先级信息,事件,定时器信息,私有数据指针。在RT-Thread中提供的线程接口函数都是环绕线程的各种状态展开的。

/*

* 线程的状态定义

*/

#define RT_THREAD_INIT                  0x00                /**<
初始化状态 */

#define RT_THREAD_READY                 0x01                /**<
就绪状态 */

#define RT_THREAD_SUSPEND               0x02                /**<
挂起状态 */

#define RT_THREAD_RUNNING               0x03                /**<
执行状态 */

#define RT_THREAD_BLOCK                 RT_THREAD_SUSPEND   /**<
堵塞状态 */

#define RT_THREAD_CLOSE                 0x04                /**<
关闭/结束状态 */

处于初始化状态的接口函数有:rt_thread_init,rt_thread_create

这两个函数的差别在于一个是静态的初始化一个线程实体,还有一个是动态的创建线程实体再来初始化。

/*******************************************************************************************

** 函数名称: rt_thread_init

** 函数功能: 静态初始化线程实例

** 入口參数: thread 线程对象句柄

**    name 线程的名字

**    entry 线程的入口函数

**    parameter 附加參数

**    stack_start 栈底指针

**    stack_size 栈的大小

**    priority 线程的优先级

**    tick 线程的初始滴答数(能执行的时间片值)

** 返 回 值: 成功返回RT_EOK

** 调    用: rt_thread_init

*******************************************************************************************/

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_ASSERT(thread != RT_NULL);

RT_ASSERT(stack_start != RT_NULL);

/** 初始化线程内嵌的对象结构 */

rt_object_init((rt_object_t)thread, RT_Object_Class_Thread,
name);

/** 初始化线程实例 */

return _rt_thread_init(thread,

name,

entry,

parameter,

stack_start,

stack_size,

priority,

tick);

}

/*******************************************************************************************

** 函数名称: rt_thread_create

** 函数功能: 动态的创建线程

** 入口參数: name 线程的名字

**    entry 线程的入口

**    parameter 附加參数

**    stack_size 线程栈的大小

**    priority 线程的优先级

**    tick 线程的初始化滴答数

** 返 回 值: 线程对象句柄

** 调    用:

*******************************************************************************************/

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)

{

struct rt_thread *thread;

void *stack_start;

/** 分配线程对象 */

thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread,
name);

if (thread == RT_NULL)

return RT_NULL;

/** 分配线程的栈 */

stack_start = (void *)RT_KERNEL_MALLOC(stack_size);

if (stack_start == RT_NULL) {

rt_object_delete((rt_object_t)thread);

return RT_NULL;

}

/** 初始化线程实例 */

_rt_thread_init(thread,

name,

entry,

parameter,

stack_start,

stack_size,

priority,

tick);

return thread;

}

终于都调用到_rt_thread_init函数:

/*******************************************************************************************

** 函数名称: _rt_thread_init

** 函数功能: 初始化线程实例

** 入口參数: thread 线程对象句柄

**    name 线程的名字

**    entry 线程的入口函数

**    parameter 附加參数

**    stack_start 栈底指针

**    stack_size 栈的大小

**    priority 线程的优先级

**    tick 线程的初始滴答数(能执行的时间片值)

** 返 回 值: 成功返回RT_EOK

** 调    用: rt_thread_init

*******************************************************************************************/

static 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_list_init(&(thread->tlist));

thread->entry = (void *)entry;

thread->parameter = parameter;

thread->stack_addr = stack_start;

thread->stack_size = (rt_uint16_t)stack_size;

/** 初始化线程的栈 */

rt_memset(thread->stack_addr, ‘#‘, thread->stack_size);

thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,

(void *)((char *)thread->stack_addr + thread->stack_size - 4),

(void *)rt_thread_exit);

RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX);

thread->init_priority    = priority;

thread->current_priority = priority;

thread->init_tick      = tick;

thread->remaining_tick = tick;

thread->error = RT_EOK;

/** 创建线程时,线程处于INIT状态 */

thread->stat  = RT_THREAD_INIT;

thread->cleanup   = 0;

thread->user_data = 0;

/** 初始化线程内嵌的定时器 */

rt_timer_init(&(thread->thread_timer),

thread->name,

rt_thread_timeout,

thread,

0,

RT_TIMER_FLAG_ONE_SHOT);

return RT_EOK;

}

在这个函数中有几点须要注意:

1.线程的栈是怎样初始化的?

线程的栈是这样布局的:

-----------

| Entry   |        <--- 线程的入口函数

-----------

|  LR     |        <--- 返回地址

-----------

|  R12    |        <--- 通用寄存器

-----------

|  R11    |

-----------

|  R10    |

-----------

|  R9     |

-----------

|  R8     |

-----------

|  R7     |

-----------

|  R6     |

-----------

|  R5     |

-----------

|  R4     |

-----------

|  R3     |

-----------

|  R2     |

-----------

|  R1     |

-----------

|  R0     |

-----------

|  CPSR   |    <--- 当前程序状态寄存器

-----------

|  SPSR   |    <--- 保存程序状态寄存器

-----------

2.线程内嵌的定时器的目的?

线程内嵌定时器来实现线程状态的改变。比方当须要让线程休眠多少个时钟滴答时,能够将线程设置为挂起状态。然后设置定时器的超时时间启动定时器。这样当定时器超市就能唤醒线程

3.此时线程是否具备了执行条件?

初始化后线程的状态为INIT状态,并不能执行,要转换成就绪状态需调用rt_thread_startup

设置线程为就绪状态的接口函数有:rt_thread_control。rt_thread_resume。rt_thread_timeout

rt_thread_control

rt_schedule_insert_thread

thread->stat = RT_THREAD_READY

rt_thread_resume

rt_schedule_insert_thread

thread->stat = RT_THREAD_READY

rt_thread_timeout

rt_schedule_insert_thread

thread->stat = RT_THREAD_READY

能够发现设置线程为就绪状态的接口函数实际为rt_schedule_insert_thread

/*********************************************************************************************************

** 函数名称: rt_schedule_insert_thread

** 函数功能: 将线程插入到就绪队列中

** 入口參数: thread 线程对象句柄

** 返 回 值: 无

** 调    用:

*********************************************************************************************************/

void rt_schedule_insert_thread(struct rt_thread* thread)

{

register rt_base_t temp;

/** 參数检查 */

RT_ASSERT(thread != RT_NULL);

/** 禁止全局中断 */

temp = rt_hw_interrupt_disable();

/** 设置线程的状态为就绪态 */

thread->stat = RT_THREAD_READY;

/** 将线程插入到优先级队列中 */

rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),

&(thread->tlist));

#if RT_THREAD_PRIORITY_MAX <= 32

RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,
("insert thread[%.*s], the priority: %d\n",

RT_NAME_MAX, thread->name, thread->current_priority));

#else

RT_DEBUG_LOG(RT_DEBUG_SCHEDULER,

("insert thread[%.*s], the priority: %d 0x%x %d\n",

RT_NAME_MAX,

thread->name,

thread->number,

thread->number_mask,

thread->high_mask));

#endif

/** 设置就绪表和就绪组 */

#if RT_THREAD_PRIORITY_MAX > 32

rt_thread_ready_table[thread->number]
|= thread->high_mask;

#endif

rt_thread_ready_priority_group |=
thread->number_mask;

/** 使能全局中断 */

rt_hw_interrupt_enable(temp);

}

在函数中除了将线程设置为就绪状态外,还有几个动作须要关注:

1.将线程增加线程优先级链表中。在RT-Thread支持的优先级个数能够为32或256,但系统所支持的线程数目并没有限制。

因此,处于同一优先级的线程是能够多个的,这些线程将以链表连接起来。这些具有同样优先级的线程的调度方式为时间片调度。

rt_thread_priority_table[256]

----------

|   0    |----->线程2 ---> 线程5 --->...

----------

|   1    |

----------

.........

----------

|   253  | ---> 线程100 --->线程3

----------

|   254  |

----------

|   255  | ---> 线程50

----------

2.设置了全局的就绪表和就绪组

设置线程为挂起状态的接口函数有:rt_thread_startup,rt_thread_suspend

rt_thread_startup

thread->stat = RT_THREAD_SUSPEND        /**
设置线程的状态为挂起状态 */

rt_thread_suspend

thread->stat = RT_THREAD_SUSPEND

rt_schedule_remove_thread

设置线程为挂起状态的接口函数有:rt_thread_exit。rt_thread_detach,rt_thread_delete

rt_thread_delete

rt_schedule_remove_thread

thread->stat = RT_THREAD_CLOSE

rt_list_insert_after(&rt_thread_defunct,
&(thread->tlist))

rt_thread_detach

rt_schedule_remove_thread

rt_timer_detach

thread->stat = RT_THREAD_CLOSE

rt_object_detach

rt_thread_exit

rt_schedule_remove_thread

thread->stat = RT_THREAD_CLOSE

rt_timer_detach

时间: 2024-10-13 01:21:08

RT-Thread内核之线程调度(三)的相关文章

Linux内核设计第三周——构造一个简单的Linux系统

Linux内核设计第三周 ——构造一个简单的Linux系统 一.知识点总结 计算机三个法宝: 存储程序计算机 函数调用堆栈 中断 操作系统两把宝剑: 中断上下文的切换 进程上下文的切换 linux内核源代码分析 arch/目录保存支持多种CPU类型的源代码 其中的关键目录包括:Documentation.drivers.firewall.fs(文件系统).include init目录:含有main.c,内核启动相关的代码基本都在init目录下 start_kernal()函数为启动函数,初始化内

LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS

LINUX内核分析第三周学习总结——构造一个简单的Linux系统MenuOS 黄韧(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 回顾: [计算机三个法宝] 1)存储程序计算机 2)函数调用堆栈 3)中断 [操作系统两把宝剑] 1)中断上下文的切换:保存现场和恢复现场 2)进程上下文的切换 一.使用gdb跟踪调试内核从start_kernel到init进程启动 使用实验楼的虚拟机打开

RT Thread学习历程(1):串口乱码问题

因为学习实时系统,最近接触到RT Thread. 把RT Thread官网上的示例代码烧录到STM32的板子上之后,在串口软件上接收到的全是乱码,一开始以为是串口软件的问题,换了2个软件之后情况都一样,最后发现是晶振的问题,我用的是STM32F407VGT6,晶振要设为8MHz,代码相应的设置晶振的部分也要修改.

20135327郭皓--Linux内核分析第三周 构造一个简单的Linux系统MenuOS

Linux内核分析第三周  构造一个简单的Linux系统MenuOS 前提回顾 1.计算机是如何工作的三个法宝 1.存储程序计算机 2.函数调用堆栈 3.中断 2.操作系统的两把宝剑 中断上下文的切换 进程上下文的切换 第一讲  Linux内核源代码介绍 arch目录包括了所有和体系结构相关的核心代码.它下面的每一个子目录都代表一种Linux支持的体系结构,例如i386就是Intel CPU及与之相兼容体系结构的子目录.PC机一般都基于此目录. init目录包含核心的初始化代码(不是系统的引导代

Linux内核分析(三)----初识linux内存管理子系统

Linux内核分析(三) 昨天我们对内核模块进行了简单的分析,今天为了让我们今后的分析没有太多障碍,我们今天先简单的分析一下linux的内存管理子系统,linux的内存管理子系统相当的庞大,所以我们今天只是初识,只要对其进行简单的了解就好了,不会去追究代码,但是在后面我们还会对内存管理子系统进行一次深度的分析. 在分析今天的内容之前,我们先来看出自http://bbs.chinaunix.net/thread-2018659-2-1.html的一位大神做的内存管理图,真心佩服大神.其实这张图可以

变量赋值(非引用) php内核的实现(三)

<?php $a=1; $b=&a; $c=2; $d=$c; $c=$b; 结论: 保存左值的指针,为内存回收做准备,同时该指针会被再次赋值 1)左值不是一个引用 1.1)如果左值 refcount_gc为1,说明左值被赋过值, 1.1.1)右值为引用 ,进入第2步 1.1.2)右值不是引用,refcount_gc加1,将右值拷贝给左值 1.2)如果不为1,说明第一次出现,或者被别的变量共同使用了 zval, 其refcount_gc减1 ,将左值GC buffer中 (由GC判断是否需要

java基础知识回顾之java Thread类学习(三)--java线程实现常见的两种方式实现好处:

总结:实现Runnable接口比继承Thread类更有优势: 1.因为java只能单继承,实现Runnable接口可以避免单继承的局限性 2.继承Thread类,多个线程不能处理或者共享同一个资源,但是实现Runnable接口可以处理同一个资源. 下面我们做个测试:验证下.车站的售票系统售票的例子,车站的各个售票口相当于各个线程,我们先使用第一种方法几继承Thread类的方式实现: 代码如下: package com.lp.ecjtu.Thread; /** * * @author Admini

RT-thread内核之线程调度器分析

一.前言 RT-Thread中提供的线程调度器是基于全抢占式优先级的调度,在系统中除了中断处理函数.调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身.系统总共支持256个优先级(0 - 255,数值越小的优先级越高,0为最高优先级,255分配给空闲线程使用,一般用户不使用.在一些资源比较紧张的系统中,可以根据情况选择只支持8个或32个优先级的系统配置).在系统中,当有比当前线程优先级还要高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处

RT-thread内核之线程调度器

http://www.cnblogs.com/King-Gentleman/p/4278012.html 一.前言 RT-Thread中提供的线程调度器是基于全抢占式优先级的调度,在系统中除了中断处理函数.调度器上锁部分的代码和禁止中断的代码是不可抢占的之外,系统的其他部分都是可以抢占的,包括线程调度器自身.系统总共支持256个优先级(0 - 255,数值越小的优先级越高,0为最高优先级,255分配给空闲线程使用,一般用户不使用.在一些资源比较紧张的系统中,可以根据情况选择只支持8个或32个优先