线程(任务及空闲)与BIOS系统的交互配置问题

这篇具有很好参考价值的文章主要介绍了线程(任务及空闲)与BIOS系统的交互配置问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、理解可重入函数

1、前言

在中断处理函数中调用了printf函数,因为中断处理函数调用了不可重入函数,导致中断丢失和系统位置错误,直接导致嵌入式linux系统应用进程中的所有线程停掉,进而导致看门狗进程得不到喂狗,设备重启。

2、什么是不可重入函数?

可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区、中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

满足下列条件的函数多数是不可重入的:

函数体内使用了静态(static)的数据结构;函数体内调用了malloc()或者free()函数;函数体内调用了标准I/O函数

举例:

A.可重入函数

void strcpy(char *lpszDest, char *lpszSrc)
{
    while(*lpszDest++=*lpszSrc++);//使用的局部变量
    *dest=0;
}

B.不可重入函数1

char cTemp;//全局变量
void SwapChar1(char *lpcX,char *lpcY)
{
    cTemp=*lpcX;
    *lpcX=*lpcY;
    lpcY=cTemp;//访问了全局变量
}

C.不可重入函数2

void SwapChar2(char *lpcX,char *lpcY)
{
    static char cTemp;//静态局部变量
    cTemp=*lpcX;
    *lpcX=*lpcY;
    lpcY=cTemp;//使用了静态局部变量
}

3、为什么中断处理函数不能直接调用不可重入函数?

在多任务系统下,中断可能在任务执行的任何时间发生;如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入的。

在中断前后不都要保存和恢复上下文吗,怎么会出现函数所依赖的环境发生改变了呢?我们知道中断时确实保存一些上下文,但是仅限于返回地址、CPU寄存器等之类的少量上下文,而函数内部使用的诸如全局或静态变量、buffer等并不在保护之列,所以如果这些值在函数被中断期间发生了改变,那么当函数回到断点继续执行时,其结果就不可预料了。

在中断处理函数中调用有互斥锁保护的全局变量,如果恰好该变量正在被另一个线程调用,会导致中断处理函数不能及时返回,导致中断丢失等严重问题。并且在多线程环境中使用,在没有加锁的情况下,对同一段内存块进行并发读写,就会造成segmentfault/coredump之类的问题。总而言之,中断处理函数做的事情越简单越好。

4、如何写出可重入的函数?

在函数体内不访问那些全局变量;如果必须访问全局变量,记住利用互斥信号量来保护全局变量,或者调用该函数前关中断,调用后再开中断;不使用静态局部变量;坚持只使用缺省态(auto)局部变量;在和硬件发生交互的时候,切记关闭硬件中断,完成交互记得打开中断;不能调用任何不可重入函数;谨慎使用堆栈,最好先使用前先OS_ENTER_KERNAL。

二、任务

SYS/BIOS 系统内核组件;0~31优先级(默认0~15,优先级0被空闲线程使用,任务最低优先级为1);无限制数量(内存允许情况下);独立内存堆栈;更先进的调度技术(可以为等待某一时间的发生而被挂起;任务会被其他更高优先级的线程打断,所以图中的C函数必须是可重入函数);数量和状态可以在程序执行时动态的更改;优先级可以动态的修改。

         线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

每个任务都有自己独立的堆栈,因此任务是可以被挂起的。内核会为每个任务对象维护一份处理器关键寄存器的副本。由于每个任务都有自己独立的堆栈,所以任务的开销相对于其它线程来说较大,需要更大的内存。

任务线程内存消耗:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

三、空闲(后台)线程

SYS/BIOS系统内核组件;非实时性线程;当且仅当没有任何其他线程(HWI/SWI/TASK运行时才会运行);所有空闲线程运行在同一个优先级;有数量限制;可以被任何其它线程随时抢占;默认任务堆栈,如果任务线程被禁用使用系统堆栈;一个接一个运行,每一个空闲线程函数都会从开始执行到结束,所有函数执行完成之后再从第一个函数开始执行,周而复始;不要在空闲线程的函数中使用阻塞语句(例如,Task_sleep()语句)。

四、BIOS系统的相关操作

BIOS系统具有良好的可移植性,可以在其他平台上使用。

任务模块:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

空闲线程模块:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

任务线程执行:

linux系统的非实时版本执行多线程采用的是轮询的方法,执行顺序是随机的;而BIOS系统采用的是抢占式的方式,也就是说每个线程的执行顺序一定是确定的。

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

任务线程挂钩函数:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

任务线程配置:

如果任务在整个生命周期内都需要,一般通过静态配置。动态配置任务线程,灵活性高,且资源浪费少。

静态配置:

var Task = xdc.useModule('ti.sysbios.knl.Task');
var task0Params = new Task.Params();
task0Params.instance.name = "task0";
Program.global.task0 = Task.create("&taskMain",task0Params);

动态配置:

#include <ti/sysbios/knl/Task.h>
Task_Handle task;
Error_Block eb;
Error_init(&eb);
task = Task_create(taskMain,NULL,&eb);
if(task == NULL)
{
    System_printf("Task_create() failed!\n");
}

如果Task_create中的参数为NULL,则默认使用.cfg中的相关参数,以下为任务参数。

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

任务线程相关函数:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

任务线程状态:

任务中的堆栈非常重要,可以获取堆栈状态。

Task_Stat statbuf;
Task_stat(Task_self(),&statbuf);
if(statbuf.used > (statbuf.stackSize * 9 / 10))
{
    System_printf("Over 90% of task's stack is in use.\n");
}

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

printf与System_printf的区别:

printf在运行时比System_printf更耗费系统资源,在使用时需要加\r\n,才可以立刻打印到终端。System_printf不一定立刻打印到终端,涉及一些交互资源的堆栈,如果需要立刻打印到终端,则需要加System_flush()语句。

printf("Exit taskMain()\r\n");

System_printf("Exit taskMain()\n");
System_flush();

五、实验结果与BIOS系统的相关配置

情况一:两个任务线程

/*
 * task.c
 *
 *  Created on: 2024-3-11
 *      Author: ouc
 */
#include <stdio.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Memory.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/IHeap.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>

// Task 1
void TaskMain1()
{
	System_printf("Enter the TaskMain1!\n");
	System_flush();
};

// Task 2
void TaskMain2()
{
	System_printf("Enter the TaskMain2!\n");
	System_flush();
};

// Idle 1
void IdleMain1()
{
	System_printf("Enter the IdleMain1!\n");
	System_flush();
};

// Idle 2
void IdleMain2()
{
	System_printf("Enter the IdleMain2!\n");
	System_flush();
};
int main()
{

	Task_Handle task1;
	Task_Handle task2;
	Error_Block eb;
	Error_init(&eb);
	task1 = Task_create(TaskMain1,NULL,&eb);
	task2 = Task_create(TaskMain2,NULL,&eb);
	/*Task_stat(Task_self(),&statbuf);
	if(statbuf.used > (statbuf.stackSize * 9 / 10))
	{
		System_printf("Over 90% of task's stack is in use.\n");
		System_flush();
		BIOS_exit(0);
	};*/
	if(task1 == NULL)
	{
		System_printf("Task_create() failed!\n");
		System_flush();
		BIOS_exit(0);
	};
	if(task2 == NULL)
	{
		System_printf("Task_create() failed!\n");
		System_flush();
		BIOS_exit(0);
	};
	BIOS_start();
	return (0);
}

cfg Script代码:

var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
var Memory = xdc.useModule('xdc.runtime.Memory');
var Task = xdc.useModule('ti.sysbios.knl.Task');
var Idle = xdc.useModule('ti.sysbios.knl.Idle');
var BIOS = xdc.useModule('ti.sysbios.BIOS');
var heapMem0Params = new HeapMem.Params();
heapMem0Params.instance.name = "Systemheap";
heapMem0Params.size = 262144;
heapMem0Params.align = 8;
Program.global.Systemheap = HeapMem.create(heapMem0Params);
Memory.defaultHeapInstance = Program.global.Systemheap;
Program.sectMap["Systemheap"] = new Program.SectionSpec();
Program.sectMap["Systemheap"].loadSegment = "L2SRAM";
Program.sectMap["Systemheap"].loadAlign = undefined;
Program.sectMap["Systemheap"].runSegment = "L2SRAM";
Program.sectMap["Systemheap"].type = "COPY";
Program.sectMap["Systemheap"].loadAddress = undefined;
Program.sectMap["Systemheap"].fill = undefined;
Idle.idleFxns[0] = null;
Idle.idleFxns[1] = null;
Idle.idleFxns[2] = null;

运行结果:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

分析:若创建任务线程时,未传入任务参数,即未配置任务优先级等参数,按照代码任务创建先后,运行线程。

情况二:两个空闲线程

/*
 * task.c
 *
 *  Created on: 2024-3-11
 *      Author: ouc
 */
#include <stdio.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Memory.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/IHeap.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>

// Task 1
void TaskMain1()
{
	System_printf("Enter the TaskMain1!\n");
	System_flush();
};

// Task 2
void TaskMain2()
{
	System_printf("Enter the TaskMain2!\n");
	System_flush();
};

// Idle 1
void IdleMain1()
{
	System_printf("Enter the IdleMain1!\n");
	System_flush();
};

// Idle 2
void IdleMain2()
{
	System_printf("Enter the IdleMain2!\n");
	System_flush();
};
int main()
{

	/*Task_Handle task1;
	Task_Handle task2;
	Error_Block eb;
	Error_init(&eb);
	task1 = Task_create(TaskMain1,NULL,&eb);
	task2 = Task_create(TaskMain2,NULL,&eb);
	Task_stat(Task_self(),&statbuf);
	if(statbuf.used > (statbuf.stackSize * 9 / 10))
	{
		System_printf("Over 90% of task's stack is in use.\n");
		System_flush();
		BIOS_exit(0);
	};
	if(task1 == NULL)
	{
		System_printf("Task_create() failed!\n");
		System_flush();
		BIOS_exit(0);
	};
	if(task2 == NULL)
	{
		System_printf("Task_create() failed!\n");
		System_flush();
		BIOS_exit(0);
	};*/
	BIOS_start();
	return (0);
}

cfg Script代码:

var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
var Memory = xdc.useModule('xdc.runtime.Memory');
var Task = xdc.useModule('ti.sysbios.knl.Task');
var Idle = xdc.useModule('ti.sysbios.knl.Idle');
var BIOS = xdc.useModule('ti.sysbios.BIOS');
var heapMem0Params = new HeapMem.Params();
heapMem0Params.instance.name = "Systemheap";
heapMem0Params.size = 262144;
heapMem0Params.align = 8;
Program.global.Systemheap = HeapMem.create(heapMem0Params);
Memory.defaultHeapInstance = Program.global.Systemheap;
Program.sectMap["Systemheap"] = new Program.SectionSpec();
Program.sectMap["Systemheap"].loadSegment = "L2SRAM";
Program.sectMap["Systemheap"].loadAlign = undefined;
Program.sectMap["Systemheap"].runSegment = "L2SRAM";
Program.sectMap["Systemheap"].type = "COPY";
Program.sectMap["Systemheap"].loadAddress = undefined;
Program.sectMap["Systemheap"].fill = undefined;
Idle.idleFxns[0] = null;
Idle.idleFxns[1] = "&IdleMain1";
Idle.idleFxns[2] = "&IdleMain2";

运行结果1:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

分析:不同空闲线程之间存在优先级先后的顺序

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

运行结果2:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

情况三:一个任务线程、一个空闲线程

/*
 * task.c
 *
 *  Created on: 2024-3-11
 *      Author: ouc
 */
#include <stdio.h>
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Memory.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/IHeap.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>

// Task 1
void TaskMain1()
{
	System_printf("Enter the TaskMain1!\n");
	System_flush();
};

// Task 2
void TaskMain2()
{
	System_printf("Enter the TaskMain2!\n");
	System_flush();
};

// Idle 1
void IdleMain1()
{
	System_printf("Enter the IdleMain1!\n");
	System_flush();
};

// Idle 2
void IdleMain2()
{
	System_printf("Enter the IdleMain2!\n");
	System_flush();
};
int main()
{

	Task_Handle task1;

	Error_Block eb;
	Error_init(&eb);
	task1 = Task_create(TaskMain1,NULL,&eb);
	/*task2 = Task_create(TaskMain2,NULL,&eb);
	Task_stat(Task_self(),&statbuf);
	if(statbuf.used > (statbuf.stackSize * 9 / 10))
	{
		System_printf("Over 90% of task's stack is in use.\n");
		System_flush();
		BIOS_exit(0);
	};*/
	if(task1 == NULL)
	{
		System_printf("Task_create() failed!\n");
		System_flush();
		BIOS_exit(0);
	};
	/*if(task2 == NULL)
	{
		System_printf("Task_create() failed!\n");
		System_flush();
		BIOS_exit(0);
	};*/
	BIOS_start();
	return (0);
}

cfg Script代码:

var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
var Memory = xdc.useModule('xdc.runtime.Memory');
var Task = xdc.useModule('ti.sysbios.knl.Task');
var Idle = xdc.useModule('ti.sysbios.knl.Idle');
var BIOS = xdc.useModule('ti.sysbios.BIOS');
var heapMem0Params = new HeapMem.Params();
heapMem0Params.instance.name = "Systemheap";
heapMem0Params.size = 262144;
heapMem0Params.align = 8;
Program.global.Systemheap = HeapMem.create(heapMem0Params);
Memory.defaultHeapInstance = Program.global.Systemheap;
Program.sectMap["Systemheap"] = new Program.SectionSpec();
Program.sectMap["Systemheap"].loadSegment = "L2SRAM";
Program.sectMap["Systemheap"].loadAlign = undefined;
Program.sectMap["Systemheap"].runSegment = "L2SRAM";
Program.sectMap["Systemheap"].type = "COPY";
Program.sectMap["Systemheap"].loadAddress = undefined;
Program.sectMap["Systemheap"].fill = undefined;
Idle.idleFxns[0] = null;
Idle.idleFxns[1] = "&IdleMain1";
Idle.idleFxns[2] = null;

运行结果:

线程(任务及空闲)与BIOS系统的交互配置问题,学习,dsp开发,c语言,嵌入式硬件

分析:任务线程的优先级大于空闲线程文章来源地址https://www.toymoban.com/news/detail-841812.html

到了这里,关于线程(任务及空闲)与BIOS系统的交互配置问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [嵌入式系统-32]:RT-Thread -17- 任务、进程、线程的区别

    目录 一、基本概念澄清 1.1 任务 1.2 进程 1.3 线程 1.4 比较 1.5 任务VS进程 1.6 进程 VS 线程 1.7 任务 进程 线程 发展历史 任务(Task): 进程(Process): 线程(Thread): 发展趋势: 二、不同操作系统中任务、进程、线程 2.1 Linux:没人任务,只有进程与线程 进程相关函数: 线程

    2024年02月21日
    浏览(45)
  • druid之连接空闲超时问题FIX

    彼时的少年站在成长的尽头,回首过去,一路崎岖早已繁花盛开 druid 是一个用于 Java 的高效数据库连接池,它提供了强大的监控和扩展功能。 mysql数据库等待超时时间(wait_timeout)是28800,也就是8小时,而druid连接池参数max-wait是30000 连接空闲超时问题的原因通常与连接池和

    2024年02月08日
    浏览(39)
  • 【Qt 底层之事件驱动系统】深入理解 Qt 事件机制:主事件循环与工作线程的交互探究,包括 QML 的视角

    在探讨 Qt 的世界时,我们不仅是在讨论一种编程框架,更是在探索一种将复杂技术细节隐藏于幕后、让开发者专注于创造性工作的艺术形式。正如著名的计算机科学家 Edsger Dijkstra 所言:“简洁是复杂性的先决条件。” 在这一章节中,我们将探讨 Qt 事件机制的基础概念,这

    2024年02月22日
    浏览(55)
  • GPTs的创建与使用,自定义GPTs中的Actions示例用法 定义和执行特定任务的功能模块 通过API与外部系统或服务的交互

    Logo:自动生成 Name 介绍 Description 介绍 Instructions 要求或命令等 比如用中文回复,角色。 Knowledge 上传你的知识库,如果你有某一垂直行业的数据,基于数据来回答。比如我有某个芯片的指令集。 Capabilities 都要 Actions:就这个难以理解一点,下面详说含义用法。 Addtional Setting

    2024年02月04日
    浏览(44)
  • 人机交互学习-6 交互式系统的设计

    Allan Cooper建议不要过早地把重点放在小细节、小部件和精细的交互上会妨碍产品的设计,应先站在一个高层次上关注用户界面和相关行为的整体结构 Allan Cooper提出的交互框架不仅 定义了高层次的屏幕布局 ,同时定义了 产品的工作流、行为和组织 。它包括了6个主要步骤:

    2024年02月09日
    浏览(61)
  • 人机交互学习-5 交互式系统的需求

    关于目标产品的一种陈述,它指定了产品应做什么,或者应如何工作 应该是具体、明确和无歧义的 搜集数据 解释数据 提取需求 注:了解 功能不同 智能冰箱:应能够提示黄油已用完 字处理器:系统应支持多种格式 物理条件不同 移动设备运行的系统应尽可能小,屏幕显示限

    2024年02月09日
    浏览(58)
  • STM32 cubemx配置DMA+空闲中断接收不定长数据

    本篇文章给大家讲解一下DMA+串口空闲中断接收串口不定长数据,之前我们也是讲解过串口接收不定长数据的,那么本篇文章的话将使用DMA来接收不定长数据。 串口空闲中断是指在串口接收到数据后,在数据的传输结束之后,在一段连续的空闲时间内没有接收到新数据时触发

    2024年02月19日
    浏览(56)
  • Django实战项目-学习任务系统-任务管理

    接着上期代码框架,开发第3个功能,任务管理,再增加一个学习任务表,用来记录发布的学习任务的标题和内容,预计完成天数,奖励积分和任务状态等信息。 第一步:编写第三个功能-任务管理 1,编辑模型文件: ./mysite/study_system/models.py: 2,编辑urls配置文件: ./mysite/stu

    2024年02月06日
    浏览(48)
  • 空闲空间管理和文件系统结构的优化策略

    关于空闲空间的管理,前面提到的是已被占用的数据块的组织和管理。接下来要解决的问题是,当我要保存一个数据块时,应该将其放在硬盘的哪个位置。难道需要扫描所有的块,随意找个空的地方放吗? 然而,这种方式效率太低了。因此,我们需要引入一种管理磁盘空闲空

    2024年02月09日
    浏览(36)
  • Django实战项目-学习任务系统-定时任务管理

    接着上期代码框架,开发第4个功能,定时任务管理,再增加一个学习定时任务表,主要用来设置周期重复性的学习任务,定时周期,定时时间,任务标题和内容,预计完成天数,奖励积分和任务状态等信息。 现实中学习一门课程或一项技能知识,需要很长时间的学习积累才

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包