• 嵌入式实时操作系统的设计与开发 (线程操作学习)


    在aCoral操作系统中,线程退出采用了和Linux一样的方式,线程函数不用死等或显示调用退出相关函数,也就是说用户不用担心函数执行完后的事情。

    uc/OS II任务函数与退出

    void test(void *ptr){
    	Do_something();
    	while(1);
    }
    
    void test(void *ptr){
    	Do_something();
    	EXIT();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    void acoral_thread_exit(){
    	acoral_kill_thread(acoral_cur_thread);
    }
    
    • 1
    • 2
    • 3
    typedef struct{
    	acoral_res_t res; //event也是一种资源
    	unsigned char type; //ACORAL_EVENT_SEM或ACORAL_EVENT_MUTEX
    	int count; //
    	acoral_list_t wait_queue;
    	char *name;
    	void *data;
    }acoral_evt_t;
    
    void acoral_kill_thread(acoral_thread_t *thread){
    	acoral_evt_t *evt;
    	acoral_enter_critical();
    	if(thread->state & ACORAL_THREAD_STATE_SUSPEND)
    	{
    		evt = thread->evt;
    		if(thread->state & ACORAL_THREAD_STATE_DELAY){
    			acoral_list_del(&thread->waiting);
    		}else{
    			if(evt!=NULL){
    				acoral_evt_queue_del(thread);
    			}
    		}
    	}
    	acoral_unrdy_thread(thread); //将线程从就绪队列中取下
    	acoral_release_thread1(thread);
    	acoral_exit_critical();
    	acoral_sched();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    如果线程处于挂起状态,则需要从相关链表中取下。

    • 如果是延时挂起,则从延时队列取下。
    • 如果是事件等待,则从事件队列取下。
    void acoral_unrdy_thread(acoral_thread_t *thread){
    	if(!(ACORAL_THREAD_STATE_READY&thread->state))
    		return;
    	acoral_rdyqueue_del(thread);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    void acoral_rdyqueue_del(acoral_thread_t *thread)
    {
    	acoral_rdy_queue_t *rdy_queue;
    	rdy_queue = &acoral_ready_queues;
    	acoral_prio_queue_del(rdy_queue, thread->prio, &thread->ready);
    	thread->state &= ~ACORAL_THREAD_STATE_READY;
    	thread->state &= ~ACORAL_THREAD_STATE_RUNNING;
    	thread->state |= ACORAL_THREAD_STATE_SUSPEND;
    	acoral_set_need_sched(true);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    extern int daemon_id;
    void acoral_release_thread1(acoral_thread_t *thread){
    	acoral_list_t *head;
    	acoral_thread_t *daem;
    	thread->sate = ACORAL_THREAD_STATE_EXIT;
    	head = &acoral_res_release_queue;
    	acoral_list_add2_tail(&thread->waiting, head);
    	daem = (acoral_thread_t *)acoral_get_res_by_id(daemon_id);
    	acoral_rdy_thread(daem);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    将线程设置为退出状态,如果是当前线程,则只能是EXIT状态,表明还不能释放该线程的资源,如TCB,堆栈,因为仅管线程要退出了,还没有走到HAL_SWITCH_TO函数,该函数还需要堆栈。

    void daem(void *args)
    {
    	acoral_thread_t *thread;
    	acoral_list_t *head, *tmp, *tmp1;
    	head = &acoral_res_release_queue;
    	while(1)
    	{
    		for(tmp=head->next;tmp!=head;)
    		{
    			tmp1 = tmp->next;
    			acoral_enter_critical();
    			thread = list_entry(tmp, acoral_thread_t, waiting);
    			acoral_list_del(tmp);
    			acoral_exit_critical();
    			tmp = tmp1;
    			if(thread->state == RELEASE)
    			{
    				acoral_release_thread((acoral_res_t *)thread);
    			}else{
    				acoral_enter_critical();
    				tmp1 = head->prev;
    				acoral_list_add2_tail(&thread->waiting, head); /**/
    				acoral_exit_critical();
    			}
    		}
    		acoral_suspend_self();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    挂起线程

    操作系统在运行过程中,有时需要挂起某个线程,例如,当某一线程运行时需要请求某一资源,而该资源正在被其它线程所占用,此时,用户线程需要挂起自己。

    void acoral_unrdy_thread(acoral_thread_t *thread){
    	if(!(ACORAL_THREAD_STATE_READY&thread->state))
    		return;
    	acoral_rdyqueue_del(thread);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    void acoral_rdyqueue_del(acoral_thread_t *thread)
    {
    	acoral_rdy_queue_t *rdy_queue;
    	rdy_queue = &acoral_ready_queues;
    	acoral_prio_queue_del(rdy_queue, thread->prio, &thread->ready);
    	thread->state &= ~ACORAL_THREAD_STATE_READY;
    	thread->state &= ~ACORAL_THREAD_STATE_RUNNING;
    	thread->state |= ACORAL_THREAD_STATE_SUSPEND;
    	/*设置线程所在的核可调度*/
    	acoral_set_need_sched(true);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    void acoral_prio_queue_del(acoral_rdy_queue_t *array, unsigned char prio, acoral_list_t *list){
    	acoral_list_t *queue;
    	acoral_list_t *head;
    	queue = array->queue + prio;
    	head = queue;
    	array->num--;
    	acoral_list_del(list);
    	if(acoral_list_empty())
    		acoral_clear_bit(prio,array->bitmap);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    任务挂起接口用到的地方很多,只要牵涉任务等待都会调用该函数。
    那如何区分用户是调用acoral_suspend_thread(),还是调用acoral_delay_self()导致线程suspend的呢?
    很简单,看线程TCB的waiting成员是否为空,如果因为等待时间或资源导致suspend,其waiting肯定挂在一个队列上,否则是直接调用acoral_suspend_thread()导致的suspend。

    改变线程优先级

    当多个线程互斥地访问某一共享资源的时候,可能导致优先级反转,优先级反转将造成实时调度算法的不确定性,进而影响系统实时性的确保。
    解决优先级反转的方法是优先级继承和优先级天花板,而使用这两种方式的时候,需要动态改变线程优先级。

    acoral描述线程优先级时,采用的是优先级队列,每个优先级是一个链表,因此改变优先级不是简单地将线程TCB的prio变量更改,最终要通过acoral_thread_change_prio()实现将线程挂到要设置的优先级的链表上去。

    void acoral_thread_change_prio(acoral_thread_t *thread, unsigned int prio){
    	acoral_enter_critical();
    	if(thread->state&ACORAL_THREAD_STATE_READY){
    		acoral_rdyqueue_del(thread);
    		thread->prio = prio;
    		acoral_rdyqueue_add(thread);
    	}else
    		thread->prio = prio;
    	acoral_exit_critical();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果线程处于就绪态,则将线程从就绪队列取下,改变优先级,再次将线程挂到就绪队列。

    调度策略时间处理函数

    系统启动后,晶体振荡器源源不断地产生周期性信号,通过设置,晶体振荡器可以为系统产生稳定的Ticks,也称为心跳,Tick是系统的时基,也是系统中最小的时间单位,Tick的大小可以根据晶体振荡器的精度和用户的需求进行设置。

    每当产生一个Tick,都对应着一个时钟中断服务程序ISR。
    时钟中断服务程序的具体是acoral_ticks_entry()

    void acoral_tciks_entry(int vector){
    	tick++;
    	if(acoral_start_sched==true){
    		time_delay_deal();
    		acoral_policy_delay_deal();
    		timeout_delay_deal();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    acoral_list_t time_delay_queue; //线程延时队列,调用线程delay相关函数的线程都会被加到这个队列上,等待一段具体的时间后被重新唤醒
    void time_delay_deal(){
    	acoral_list_t *tmp,*tmp1,*head;
    	acoral_thread_t *thread;
    	
    	head = &time_delay_queue;
    	if(acoral_list_empty(head))
    		return;
    	thread = list_entry(head->next,acoral_thread_t,waiting);
    	thread->delay--;
    	for(tmp=head->next;tmp!=head;){
    		thread = list_entry(tmp,acoral_thread_t,waiting);
    		if(thread->delay > 0)
    			break;
    		tmp1= tmp->next;
    		acoral_list_del(&thread->waiting);
    		tmp=tmp1;
    		thread->state &= ~ACORAL_THREAD_STATE_DELAY;
    		acoral_rdy_thread(thread);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    void acoral_policy_delay_deal(){
    	acoral_list_t *tmp,*head;
    	acoral_sched_policy_t *policy_ctrl;
    	head = &policy_list;
    	tmp = head;
    	for(tmp=head->next;tmp!=head;tmp=tmp>next)
    	{
    		policy_ctrl = list_entry(tmp,acoral_sched_policy_t,list);
    		if(policy_ctrl->delay_deal!=NULL)
    			policy_ctrl->delay_deal();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    acoral_list_t period_delay_queue;//周期线程专用延时队列
    void period_delay_deal()
    {
    	acoral_list_t *tmp,*tmp1,*head;
    	acoral_thread_t *thread;
    	period_private_data_t *private_data;
    	head = &period_delay_queue;
    	if(acoral_list_empty(head))
    		return;
    	thread = list_entry(head->next, acoral_thread_t, waiting);
    	thread->delay--;
    	for(tmp=head->next;tmp!=head;){
    		thread = list_entry(tmp,acoral_thread_t,waiting);
    		if(thread->delay > 0)
    			break;
    		private_data = thread->private_data;
    		tmp1 = tmp->next;
    		acoral_list_del(&thread->waiting);
    		tmp = tmp1;
    		if(thread->state&ACORAL_THREAD_SUSPEND){
    			thread->stack=(unsigned int *)((char *)thread->stack_buttom+thread->stack_size-4);
    			HAL_STACK_INIT(&thread->stack,private_data->route,period_thread_exit,private_data->args);
    			acoral_rdy_thread(thread);
    		}
    		period_thread_delay(thread,private_data->time);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 相关阅读:
    Codeforces Round #797 (Div. 3)个人题解
    Matter 研讨会(第二期)|乐鑫 Matter SDK 赋能客户自主开发 Matter 产品
    LabVIEW RT中的用户界面更新速度
    SpringMVC之JSON数据返回及异常处理机制
    javascript+canvas身份证背景颜色识别
    PMO大会的主办方是PMO评论
    【观察】OpenHarmony:技术先进“创新局”,持续创新“谋新篇”
    博客主题美化第二弹
    【无标题】
    系列学习前端之第 5 章:学习 ES6 ~ ES11
  • 原文地址:https://blog.csdn.net/Caramel_biscuit/article/details/133905434