Rt-Thread 移植6--多线程(KF32)

6.1 就绪列表

6.1.1 线程就绪优先级组

线程优先级表的索引对应的线程的优先级。
在这里插入图片描述
为了快速的找到线程在线程优先级表的插入和移出的位置,RT-Thread专门设计了一个线程就绪优先级组。线程就绪优先组是一个32位的整型数,每一个位对应一个优先级,最多表示32个优先级

rt_uint32_t  rt_thread_ready_priority_group;

在这里插入图片描述

6.1.2 寻找优先级最高的线程

在这里插入图片描述
在这里插入图片描述

从图中看出,第一个置1的位是位1,即表示此时就绪的线程当中,优先级最高的线程1,然后调度器从线程优先级表的索引1下去除线程1的线程控制块,从而切换到线程1.
kservice.c中

const rt_uint8_t __lowest_bit_bitmap[] =
{
    /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
    /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

/**
 * This function finds the first bit set (beginning with the least significant bit)
 * in value and return the index of that bit.
 *
 * Bits are numbered starting at 1 (the least significant bit).  A return value of
 * zero from any of these functions means that the argument was zero.
 *
 * @return return the index of the first bit set. If value is 0, then this function
 * shall return 0.
 */
int __rt_ffs(int value)
{
    if (value == 0) return 0;

    if (value & 0xff)
        return __lowest_bit_bitmap[value & 0xff] + 1;

    if (value & 0xff00)
        return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9;

    if (value & 0xff0000)
        return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17;

    return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25;
}

6.1.3 线程优先级表

scheduler.c

rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

在这里插入图片描述
将线程插入到线程优先级表和移出分别由scheduler.c的rt_schedule_insert_thread()和rt_schedule_remove_thread()这两个函数实现。

void rt_schedule_insert_thread(struct rt_thread *thread)
{
    register rt_base_t temp;


    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    /* change stat */
    thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK);

    /* insert thread to ready list */
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                          &(thread->tlist));


    /* set priority mask */


#if RT_THREAD_PRIORITY_MAX > 32
    rt_thread_ready_table[thread->number] |= thread->high_mask;
#endif
    rt_thread_ready_priority_group |= thread->number_mask;

    P_DBG("insert thread %x grout %x\n",thread,rt_thread_ready_priority_group);
    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
}

/*
 * This function will remove a thread from system ready queue.
 *
 * @param thread the thread to be removed
 *
 * @note Please do not invoke this function in user application.
 */
void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t temp;



    /* disable interrupt */
    temp = rt_hw_interrupt_disable();


    /* remove thread from ready list */
    rt_list_remove(&(thread->tlist));
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
    {

        rt_thread_ready_priority_group &= ~thread->number_mask;

    }

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);
}

6.2 修改代码

6.2.1 修改线程控制块

struct rt_thread
{
	char name[RT_NAME_MAX];
	rt_uint8_t type;
	rt_uint8_t flag;
	rt_list_t list;
	void        *sp;	          /* 线程栈指针 */
	void        *entry;	          /* 线程入口地址 */
	void        *parameter;	      /* 线程形参 */	
	void        *stack_addr;      /* 线程起始地址 */
	rt_uint32_t stack_size;       /* 线程栈大小,单位为字节 */
	
	rt_list_t   tlist;            /* 线程链表节点 */
#if TEST_USE_TICK_ENABLE
	rt_ubase_t init_tick;
	rt_ubase_t remaining_tick;
#endif
	**rt_uint8_t current_priority;
	rt_uint8_t init_priority;
	rt_uint32_t number_mask;
	rt_err_t error;
	rt_uint8_t stat;**

};

rtdef.h中定义错误码

#define RT_EOK                          0               /**< There is no error */
#define RT_ERROR                        1               /**< A generic error happens */
#define RT_ETIMEOUT                     2               /**< Timed out */
#define RT_EFULL                        3               /**< The resource is full */
#define RT_EEMPTY                       4               /**< The resource is empty */
#define RT_ENOMEM                       5               /**< No memory */
#define RT_ENOSYS                       6               /**< No system */
#define RT_EBUSY                        7               /**< Busy */
#define RT_EIO                          8               /**< IO error */
#define RT_EINTR                        9               /**< Interrupted system call */
#define RT_EINVAL                       10              /**< Invalid argument */

定义线程状态

#define RT_THREAD_INIT                  0x00                /**< Initialized status */
#define RT_THREAD_READY                 0x01                /**< Ready status */
#define RT_THREAD_SUSPEND               0x02                /**< Suspend status */
#define RT_THREAD_RUNNING               0x03                /**< Running status */
#define RT_THREAD_BLOCK                 RT_THREAD_SUSPEND   /**< Blocked status */
#define RT_THREAD_CLOSE                 0x04                /**< Closed status */
#define RT_THREAD_STAT_MASK             0x0f

修改rt_system_scheduler_init()

void rt_system_scheduler_init(void)
{



	register rt_base_t offset;
	for(offset = 0; offset < RT_THREAD_PRIORITY_MAX;offset++)
	{
		rt_list_init(&rt_thread_priority_table[offset]);
	}
	rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
	rt_current_thread = RT_NULL;
	rt_thread_ready_priority_group = 0;

	/* 初始化线程休眠列表,当线程创建好没有启动之前会被放入到这个列表 */

}

6.2.3 修改线程初始化函数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_object_init((rt_object_t)thread,RT_Object_Class_Thread,name);
	rt_list_init(&(thread->tlist));

	thread->entry = (void *)entry;
	thread->parameter = parameter;

	thread->stack_addr = stack_start;
	thread->stack_size = stack_size;

	/* 初始化线程栈,并返回线程栈指针 */
	thread->sp = (void *)rt_hw_stack_init( thread->entry,
		                                   thread->parameter,
							               (void *)((char *)thread->stack_addr + thread->stack_size - 4) );
	**thread->init_priority = priority;
	thread->current_priority = priority;
	thread->number_mask = 0;
	thread->error = RT_EOK;
	thread->stat = RT_THREAD_INIT;**

}

6.2.4 添加线程启动函数rt_thread_startup()

rt_err_t rt_thread_startup(rt_thread_t thread)
{
	thread->current_priority = thread->init_priority;
	thread->number_mask = 1L << thread->current_priority;
	thread->stat = RT_THREAD_SUSPEND;
	rt_thread_resume(thread);
	if(rt_thread_self() != RT_NULL)
	{
		rt_schedule();
	}
}
rt_err_t rt_thread_resume(rt_thread_t thread)
{
	register rt_base_t temp;
	if((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
	{
		return -RT_ERROR;
	}
	temp = rt_hw_interrupt_disable();
	rt_list_remove(&(thread->tlist));

	rt_hw_interrupt_enable(temp);
	rt_schedule_insert_thread(thread);
}

6.2.5 修改空闲线程初始化函数rt_thread_idle_init()

void rt_thread_idle_init(void)
{
	    rt_thread_init(&idle,"idle",rt_thread_idle_entry,RT_NULL,&rt_thread_stack[0],sizeof(rt_thread_stack),RT_THREAD_PRIORITY_MAX - 1);

	**rt_thread_startup(&idle);**


}

6.2.6 修改启动系统调度器函数rt_system_scheduler_start()

不再是手动指定第一个需要运行的线程,而是根据优先级来决定第一个运行的线程。

void rt_system_scheduler_start(void)
{

	register struct rt_thread *to_thread;
	register rt_ubase_t highest_ready_priority;
	highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group)-1;
	P_DBG("first start pri %d\n",highest_ready_priority);
	to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);
	rt_current_thread = to_thread;
	rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);

}

6.2.7 修改系统调度函数rt_schedule()

根据优先级来实现

void rt_schedule(void)
{

	register rt_base_t temp;
	rt_base_t level;
	register rt_ubase_t highest_ready_priority;
	struct rt_thread *to_thread;
	struct rt_thread *from_thread;
	temp = rt_hw_interrupt_disable();
	highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group)-1;
	P_DBG("read pri %d\n",highest_ready_priority);
	to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,struct rt_thread,tlist);
	P_DBG("read tgread %x\n",to_thread);
	if(to_thread != rt_current_thread)
	{
		P_DBG("!= current thread %x\n",rt_current_thread);
		rt_current_priority = (rt_uint8_t) highest_ready_priority;
		from_thread = rt_current_thread;
		rt_current_thread = to_thread;
		rt_hw_context_switch((rt_uint32_t)&from_thread->sp,(rt_uint32_t)&to_thread->sp);
		rt_hw_interrupt_enable(temp);
	}
	else
	{
		rt_hw_interrupt_enable(temp);
	}



	/* 产生上下文切换 */

}

6.2.8 修改线程阻塞函数


void rt_thread_delay(rt_tick_t tick)
{
	register rt_base_t temp;
	struct rt_thread *thread;
	temp = rt_hw_interrupt_disable(); 
	thread = rt_current_thread;
	thread->remaining_tick = tick;
	thread->stat = RT_THREAD_SUSPEND; 
	rt_thread_ready_priority_group &= ~thread->number_mask;
	rt_hw_interrupt_enable(temp);
	rt_schedule();
}

6.2.9 修改时基更i新函数rt_tick_increase()

void rt_tick_increase(void)
{
		rt_ubase_t i;
	struct rt_thread *thread;
	rt_tick++;
	for(i = 0;i < RT_THREAD_PRIORITY_MAX;i++)
	{
		thread = rt_list_entry(rt_thread_priority_table[i].next,struct rt_thread,tlist);
		if(thread->remaining_tick > 0)
		{
			thread->remaining_tick--;
			if(thread->remaining_tick == 0)
			{
				rt_thread_ready_priority_group |= thread->number_mask;
			}
		}
		rt_schedule();
	}
}

6.3 main.c


			/* 初始化线程 */
		rt_thread_init( &rt_flag1_thread,   "flag1",              /* 线程控制块 */
			                flag1_thread_entry,               /* 线程入口地址 */
			                RT_NULL,                          /* 线程形参 */
			                &rt_flag1_thread_stack[0],        /* 线程栈起始地址 */
			                sizeof(rt_flag1_thread_stack),3 );  /* 线程栈大小,单位为字节 */


			/* 将线程插入到就绪列表 */
		//rt_list_insert_before( &(rt_thread_priority_table[0]),&(rt_flag1_thread.tlist) );
		P_DBG("thread flag1 %x timer %s\n",&rt_flag1_thread,rt_flag1_thread.thread_timer.parent.name);
		rt_thread_startup(&rt_flag1_thread);
			/* 初始化线程 */

		rt_thread_init( &rt_flag2_thread,           "falg2",      /* 线程控制块 */
			                flag2_thread_entry,               /* 线程入口地址 */
			                RT_NULL,                          /* 线程形参 */
			                &rt_flag2_thread_stack[0],        /* 线程栈起始地址 */
			                sizeof(rt_flag2_thread_stack),4 );  /* 线程栈大小,单位为字节 */

/* 将线程插入到就绪列表 */
		P_DBG("thread flag1 %x timer %s\n",&rt_flag2_thread,rt_flag2_thread.thread_timer.parent.name);

		//rt_list_insert_before( &(rt_thread_priority_table[1]),&(rt_flag2_thread.tlist) );
		rt_thread_startup(&rt_flag2_thread);
			/* 启动系统调度器 */
		rt_system_scheduler_start();


/* 线程1 */
void flag1_thread_entry( void *p_arg )
{
	for( ;; )
	{
		P_DBG("flag1 thread\n");

		flag2 = 1;
		P_DBG("flag1 thread will dela1\n");
		rt_thread_delay(10);
		flag2 = 0;
		P_DBG("flag1 thread will dela2\n");
		rt_thread_delay(10);

	}
}

/* 线程2 */
void flag2_thread_entry( void *p_arg )
{
	for( ;; )
	{
		P_DBG("flag2 thread\n");

		flag2 = 1;
		rt_thread_delay(2);
		flag2 = 0;
		P_DBG("flag2 thread will dela1\n");
		rt_thread_delay(2);

	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值