当前位置: 首页 > news >正文

RTT(RT-Thread)线程管理(1.2W字详细讲解)

目录

RTT线程管理

 线程管理特点

线程工作机制

线程控制块

线程属性

线程状态之间切换

线程相关操作

创建和删除线程

创建线程

删除线程

动态创建线程实例

启动线程

初始化和脱离线程

初始化线程

脱离线程

静态创建线程实例 

线程辅助函数

获得当前线程

让出处理器资源

线程睡眠

控制线程函数

设置和删除idle线程hook函数

设置钩子函数

删除钩子函数

设置调度器hook函数

线程调度器hook函数实例


 RTT线程管理

        RT-Thread是支持多任务的操作系统,多任务是通过多线程的方式实现。线程是任务的载体,是RTT中最基本的调度单位。

        线程在运行的时候,它自己会认为独占CPU运行

        线程执行时的运行环境称为上下文(与之相对应的有中断上下文),具体来说就是各个变量和数据,包括所有的寄存器变量、堆栈、内存信息等。

 线程管理特点

        RT-Thread 线程管理的主要功能是对线程进行管理和调度,系统中总共存在两类线程,分别是系统线程用户线程,系统线程是由 RT-Thread 内核创建的线程,用户线程是由应用程序创建的线程,这两类线程都会从内核对象容器中分配线程对象,当线程被删除时,也会被从对象容器中删除。

        RT-Thread 的线程调度器是抢占式的,主要的工作就是从就绪线程列表中查找最高优先级线程,保证最高优先级的线程能够被运行,最高优先级的任务一旦就绪,总能得到 CPU 的使用权。

        当调度器调度线程切换时,先将当前线程上下文保存起来,当再切回到这个线程时,线程调度器将该线程的上下文信息恢复。(我们在切换完以后,当再次回到之前执行的线程时候,要从被打断的地方重新开始执行,所以我们要将线程上下文先保存起来)线程再被调度之前,我们要保存现场,保存完现场之后再执行高优先级的线程,在我们再调度回来的时候,再恢复现场。但这些不需要我们应用层手动来做。

线程工作机制

线程控制块

        线程控制块由结构体 struct rt_thread 表示,线程控制块是操作系统用于管理线程的一个数据结构,它会存放线程的一些信息,例如优先级、线程名称、线程状态等,也包含线程与线程之间连接用的链表结构(内核在管理多个线程的时候,将描述每个线程的结构体采用一个列表的形式来管理起来,为了方便内核后期来查找和管理),线程等待事件集合等。

struct rt_thread
{/* rt object */char       name[RT_NAME_MAX];       /**<the name of thread */rt_uint8_t  type;               /**< type of object */rt_uint8_t  flags;               /**< thread's flags */rt_list_t   list;                    /**< the object list */rt_list_t   tlist;                   /**< the thread list *//* stack point and entry */void       *sp;                     /**< stack point 栈指针*/ void       *entry;                 /**< entry */void       *parameter;          /**< parameter */void       *stack_addr;         /**< stack address point 栈地址指针*/rt_uint32_t stack_size;      /**< stack size *//* error code */rt_err_t    error;                   /**< error code */rt_uint8_t  stat;                    /**< thread status 线程状态*//* priority */rt_uint8_t  current_priority;        /**< current priority */rt_uint8_t  init_priority;           /**< initialized priority */rt_uint32_t number_mask;...rt_ubase_t  init_tick;                          /**< thread's initialized tick */rt_ubase_t  remaining_tick;                /**< remaining tick */struct rt_timer thread_timer;              /**< built-in thread timer */void (*cleanup)(struct rt_thread *tid);    /**< cleanup function when thread exit */rt_uint32_t user_data;                          /**< private user data beyond this thread */
};

其中有个对称多核处理器的功能,如果属于cortex-M系列的处理器,因为是单核,所以不使用对称多核处理器,但cortex-A系统多核支持

 注:cleanup函数指针指向的函数,会在线程退出的时候,被idle线程回调一次,执行用户设置的清理现场等工作。 

线程属性

  • 线程栈

        RT-Thread 线程具有独立的栈,当进行线程切换时,会将当前线程的上下文存在栈中,当线程要恢复运行时,再从栈中读取上下文信息,进行恢复。

  • 线程状态

可以通过查看线程控制块结构体的flags成员来判断当前线程所处状态

  • 线程优先级

        RT-Thread 最大支持 256 个线程优先级 (0~255),数值越小的优先级越高,0 为最高优先级。在一些资源比较紧张的系统中,可以根据实际情况选择只支持 8 个或 32 个优先级的系统配置;对于 ARM Cortex-M系列,普遍采用 32 个优先级。最低优先级默认分配给空闲线程使用,用户一般不使用。在系统中,当有比当前线程优先级更高的线程就绪时,当前线程将立刻被换出,高优先级线程抢占处理器运行

  • 时间片

每个线程都有时间片这个参数,但时间片仅对优先级相同的就绪态线程有效。(如果多个线程的优先级相同,对于同一优先级的线程,调度的时候根据时间片进行调度,即每个线程调度一段时间然后切换另一个线程来调度执行)

注意:

        作为一个实时系统,一个优先级明确的实时系统,如果一个线程中的程序陷入了死循环操作,那么比它优先级低的线程都将不能够得到执行。所以在实时操作系统中必须注意的一点就是:线程中不能陷入死循环操作,必须要有让出 CPU使用权的动作循环中调用延时函数或者主动挂起(两种方法都能使线程处于挂起态,挂起态是不参加线程调度的,这时我们的系统就可以调度其它线程去执行)

线程状态之间切换

 

注:就绪状态和运行状态是等同的,区别在于谁拥有线程的执行权。

就绪状态通过主动挂起等待或者主动延时一段时间,进入挂起状态,不参与线程调度

处于挂起状态的线程通过序号2中的函数可以恢复到就绪状态(如线程重启、信号释放、锁释放等等)

处于运行状态的线程通过序号1中的函数可以进入到挂起状态,这些函数与序号2中是相对的

线程相关操作

        线程相关的操作包括:创建(动态)/初始化(静态)、启动、运行、删除/脱离。

        动态线程与静态线程的区别是:动态线程是系统自动从动态内存堆上分配栈空间与线程句柄(初始化 heap 之后才能使用 create 创建动态线程),静态线程是由用户分配栈空间与线程句柄。

创建和删除线程

创建线程

参数1:用于给当前线程起名字

参数2:函数指针,指向了线程处理函数

参数3:用于给线程处理函数传递参数

参数4:要创建的线程对应线程栈的大小(指定大小之后,系统会自动动态分配空间)

参数5:线程优先级0-31(由高到低)

参数6:如果优先级相同的线程都处于就绪态,线程调度由tick来决定,按照时间片轮流调度

/*** This function will create a thread objectand allocate thread object memory* and stack.** @param name the name of thread, which shallbe unique* @param entry the entry function of thread* @param parameter the parameter of threadenter function* @param stack_size the size of thread stack* @param priority the priority of thread* @param tick the time slice if there are samepriority thread** @return the created thread object*/
rt_thread_t rt_thread_create(constchar *name,void (*entry)(void*parameter),void       *parameter,rt_uint32_tstack_size,rt_uint8_t  priority,rt_uint32_t tick)

返回值类型为线程控制块,目的是将初始化好的线程信息写到线程控制块的每个成员变量中,后期再根据线程的状态来修改线程控制块中对应信息的值

删除线程

删除线程函数对应创建线程函数

参数为线程控制块结构体的指针

返回值为错误码,如果删除成功返回RT_EOK、失败返回 -RT_ERROR

/*** This function will delete a thread. Thethread object will be removed from* thread queue and deleted from system objectmanagement in the idle thread.** @param thread the thread to be deleted** @return the operation status, RT_EOK on OK,-RT_ERROR on error*/
rt_err_t rt_thread_delete(rt_thread_tthread)

动态创建线程实例

首先创建一个通过线程块结构体指针创建一个线程结构体指针变量;调用线程创建函数,并用刚刚定义的指针变量来接收返回值

然后定义线程处理函数,并给线程创建函数填入参数,其中处理函数参数设置为NULL,栈空间设置为1024,优先级20,时间片为5(后期定时器细论)。一定要注意参数类型一一对应。

接着通过返回值判断线程是否创建成功,成功用LOG_D打印调试信息,否则用LOG_E打印失败信息。其中RT_NULL的宏值为0

最后编写完线程处理函数。设置一个while循环,在循环中通过rt_kprintf(相当于串口printf)打印输出信息。接着用rt_thread_mdelay函数进行延时1s,用于释放当前CPU资源,让线程调度器调度其它线程。

现象

通过打开串口终端,发现线程被创建成功,但是没有打印运行信息

通过输入list_thread命令查看当前存在线程,发现我们创建的线程已经存在,是处于初始状态的,如果想要运行线程,必须调用线程启动函数rt_thread_startup启动

注意:线程删除函数,我们尽量不要人为去调用。因为我们创建好线程以后,就希望线程能够一直去处理相关的事务。如果线程处理函数里面的处理操作被执行完了(函数运行结束),系统会自动调用线程删除函数来回收资源

启动线程

参数为线程控制块结构体的指针

返回值为错误码,如果删除成功返回RT_EOK、失败返回 -RT_ERROR

/*** This function will start a thread and put itto system ready queue** @param thread the thread to be started** @return the operation status, RT_EOK on OK,-RT_ERROR on error*/
rt_err_t rt_thread_startup(rt_thread_t thread)

注:当调用这个函数时,将把线程的状态更改为就绪状态,并放到相应优先级队列中等待调度。如果新启动的线程优先级比当前线程优先级高,将立刻切换到这个线程。

在创建线程后,我们如果失败就返回RT_ENOMEM,表示可能由于没有空间导致了创建线程失败。

如果创建成功,就启动线程

运行结果

通过查看线程状态,可发现当前线程处于suspend挂起的状态

这是由于我们在线程处理函数中,大部分的时间都处于休眠(延时函数),休眠就是从运行态或者就绪态切换到挂起状态

初始化和脱离线程

初始化线程

线程的初始化可以使用下面的函数接口完成,来初始化静态线程对象:

参数1:是线程控制块结构体,以指针的形式传入参数

参数2:用于给当前线程起名字

参数3:函数指针,指向了线程处理函数

参数4:用于给线程处理函数传递参数

参数5:栈的起始地址(分配好空间的线程栈的首地址)

参数6:要创建的线程对应线程栈的大小

参数7:线程优先级0-31(由高到低)

参数8:如果优先级相同的线程都处于就绪态,线程调度由tick来决定,按照时间片轮流调度

返回值与动态创建不同,如果错误这里返回的是负数错误码

注:structrt_thread *即rt_thread_t

/*** This function will initialize a thread,normally it's used to initialize a* static thread object.** @param thread the static thread object* @param name the name of thread, which shallbe unique* @param entry the entry function of thread* @param parameter the parameter of threadenter function* @param stack_start the start address ofthread stack* @param stack_size the size of thread stack* @param priority the priority of thread* @param tick the time slice if there are samepriority thread** @return the operation status, RT_EOK on OK,-RT_ERROR on error*/
rt_err_t rt_thread_init(structrt_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)

脱离线程

作用是将线程从当前的线程队列里移除出去

参数是线程控制块结构体,以指针的形式传入参数

返回值为错误码

/*** This function will detach a thread. Thethread object will be removed from* thread queue and detached/deleted fromsystem object management.** @param thread the thread to be deleted** @return the operation status, RT_EOK on OK,-RT_ERROR on error*/
rt_err_t rt_thread_detach(rt_thread_t thread)

静态创建线程实例 

首先创建好线程结构体对象,开辟好栈空间,编写线程处理函数

调用线程初始化函数

运行结果

可以发现两个线程都被创建成功并且处于初始状态,此外tshell为当前终端线程,tidle0为空闲线程,timer为定时器

我们同时启动两个线程,可以发现两个线程交替运行

我们将线程2处理函数中的延时关闭,重新编译下载

成功发现优先级高的线程2运行完之后,才调度线程1

线程辅助函数

获得当前线程

        在程序的运行过程中,相同的一段代码可能会被多个线程执行,在执行的时候可以通过下面的函数接口获得当前执行的线程句柄

/*** This function will return self thread object** @return the self thread object , failedRT_NULL*/
rt_thread_t rt_thread_self(void)

让出处理器资源

        该函数的作用让当前运行的线程让出CPU的使用权,恢复到就绪态,调度器将会选择其它处于就绪态中优先级最高的线程去调度

/*** This function will let current thread yieldprocessor, and scheduler will* choose a highest thread to run. After yieldprocessor, the current thread* is still in READY state.** @return RT_EOK*/
rt_err_t rt_thread_yield(void)

线程睡眠

        下面两个函数的作用相同,都是延时一定的时钟节拍数,让我们当前的线程处于睡眠态(阻塞态)

/*** This function will let current thread sleepfor some ticks.** @param tick the sleep ticks** @return RT_EOK*/
rt_err_t rt_thread_sleep(rt_tick_ttick)
rt_err_t rt_thread_delay(rt_tick_ttick)

第三个函数,延时一段时间ms,让我们当前的线程处于睡眠态(阻塞态)

/*** This function will let current thread delayfor some milliseconds.** @param tick the delay time** @return RT_EOK*/
rt_err_t rt_thread_mdelay(rt_int32_tms)

控制线程函数

该函数的作用是根据控制命令来控制某个线程的行为

参数1:线程句柄结构体指针

参数2:控制命令

参数3:控制命令所传入的参数;比如我们参数2传入的命令为改变线程优先级,我们就需要传入优先级数值(取地址传入),并强转为(void *)

/*** This function will control thread behaviors according to control command.** @param thread the specified thread to becontrolled* @param cmd the control command, whichincludes* RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;* RT_THREAD_CTRL_STARTUP for starting a thread;  == rt_thread_startup()* RT_THREAD_CTRL_CLOSE for delete a thread;      == rt_thread_delete()* RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.* @param arg the argument of control command** @return RT_EOK*/
rt_err_trt_thread_control(rt_thread_t thread, int cmd, void *arg)

控制命令包括:

  • RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread;
  • RT_THREAD_CTRL_STARTUP for starting a thread;  等同于 rt_thread_startup();
  • RT_THREAD_CTRL_CLOSE for delete a thread;      等同于 rt_thread_delete();
  • RT_THREAD_CTRL_BIND_CPU for bind the thread to a CPU.(将线程绑定在固定的某个CPU来执行,只支持对称多处理器的MCU)

设置和删除idle线程hook函数

RT-Thread向用户提供了一种可以设置用户自定义的空闲线程,也称钩子线程。

一般钩子函数有两个作用:

1. 在线程进行调度切换时,会执行调度,我们可以设置一个调度器钩子,这样可以在线程切换时,做一些额外的事情,这个例子是在调度器钩子函数中打印线程间的切换信息。

2. 在主线程空闲的时候做一些空闲时监控的事情,指示灯闪烁等非紧急的任务。

        在使用钩子函数时候必须保证空闲线程都不会被挂起,也就是说,rt_thread_delay()和re_sem_take() 等会导致线程挂起阻塞的函数都不能被使用在钩子函数中

传入的参数为一个函数指针,传入我们自己定义的钩子函数名

设置钩子函数
/*** @ingroup Hook* This function sets a hook function to idlethread loop. When the system performs* idle loop, this hook function should beinvoked.** @param hook the specified hook function** @return RT_EOK: set OK*        -RT_EFULL: hook list is full** @note the hook function must be simple andnever be blocked or suspend.*/
rt_err_t rt_thread_idle_sethook(void(*hook)(void))
删除钩子函数
/*** delete the idle hook on hook list** @param hook the specified hook function** @return RT_EOK: delete OK*        -RT_ENOSYS: hook was not found*/
rt_err_t rt_thread_idle_delhook(void(*hook)(void))

注意:空闲线程是一个线程状态永远为就绪态的线程,因此设置的钩子函数必须保证空闲线程在任何时刻都不会处于挂起状态,例如 rt_thread_delay(),rt_sem_take() 等可能会导致线程挂起的函数都不能使用。

设置调度器hook函数

        在整个系统的运行时,系统都处于线程运行、中断触发 - 响应中断、切换到其他线程,甚至是线程间的切换过程中,或者说系统的上下文切换是系统中最普遍的事件。有时用户可能会想知道在一个时刻发生了什么样的线程切换,可以通过调用下面的函数接口设置一个相应的钩子函数。在系统线程切换时,这个钩子函数将被调用

/*** This function will set a hook function,which will be invoked when thread* switch happens.** @param hook the hook function*/void
rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to))

通过该函数我们可以知道线程的切换关系,通过我们定义一个回调函数,在回调函数中打印相关信息。当线程进行切换的时候,会自动调用我们设置的回调函数,并将原线程和目标线程的结构体句柄传入到我们的回调函数中,从而执行相关信息操作。

线程调度器hook函数实例

我们先将之前两个线程处理函数的运行打印都设置为5次,方便待会儿查看调度效果

编写自定义hook函数,在函数中打印调度关系

设置hook函数,传入我们自定义的hook函数

运行结果

从中可以看出线程的调度关系为:首先从用户主线程切换到th2线程,然后从th2线程切换到tshell线程,接着从tshell线程切换到idle线程,最终从idle线程切换到th1线程。之后就一直是th1->idle->th2的来回切换。但最终th1线程和th2线程执行完后,会调度idle线程,此时终端继续不显示

此时键盘输入,比如输入“l”,此时终端会显示从idle线程切换到tshell,然后再从tshell切换回idle

更多的hook函数请查看官方参考手册。

相关文章:

RTT(RT-Thread)线程管理(1.2W字详细讲解)

目录 RTT线程管理 线程管理特点 线程工作机制 线程控制块 线程属性 线程状态之间切换 线程相关操作 创建和删除线程 创建线程 删除线程 动态创建线程实例 启动线程 初始化和脱离线程 初始化线程 脱离线程 静态创建线程实例 线程辅助函数 获得当前线程 让出处…...

你真的会自动化吗?Web自动化测试-PO模式实战,一文通透...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 PO模式 Page Obj…...

C# 使用堆栈实现队列

232 使用堆栈实现队列 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;、、、&#xff09;&#xff1a;pushpoppeekempty 实现 类&#xff1a;MyQueue void push(int x)将元素 x 推到队列的末尾 int pop()从队列的开头移除并返回元素 in…...

git操作:修改本地的地址

Windows下git如何修改本地默认下载仓库地址 - 简书 (jianshu.com) 详细解释&#xff1a; 打开终端拉取git时&#xff0c;会默认在git安装的地方&#xff0c;也就是终端前面的地址。 需要将代码 拉取到D盘的话&#xff0c;现在D盘创建好需要安放代码的文件夹&#xff0c;然后…...

【以图搜图】Python实现根据图片批量匹配(查找)相似图片

目的&#xff1a;可以解决在本地实现根据图片查找相似图片的功能 背景&#xff1a;由于需要查找别人代码保存的图像的命名&#xff0c;但由于数据集是cifa10图像又小又多&#xff0c;所以直接找很费眼睛&#xff0c;所以实现用该代码根据图像查找图像&#xff0c;从而得到保存…...

【无标题】JSP--Java的服务器页面

jsp是什么&#xff1f; jsp的全称是Java server pages,翻译过来就是java的服务器页面。 jsp有什么作用&#xff1f; jsp的主要作用是代替Servlet程序回传html页面的数据&#xff0c;因为Servlet程序回传html页面数据是一件非常繁琐的事情&#xff0c;开发成本和维护成本都非常高…...

【Linux】进程间通信——system V共享内存 | 消息队列 | 信号量

文章目录 一、system V共享内存1. 共享内存的原理2. 共享内存相关函数3. 共享内存实现通信4. 共享内存的特点 二、system V消息队列&#xff08;了解&#xff09;三、system V信号量&#xff08;信号量&#xff09; 一、system V共享内存 1. 共享内存的原理 共享内存是一种在…...

CentOS实现html转pdf

CentOS使用实现html转PDF&#xff0c;需安装以下软件&#xff1a; yum install wkhtmltopdf # 转换工具&#xff0c;将HTML文件或网页转换为PDFyum install xorg-x11-server-Xvfb # 虚拟的X服务器&#xff0c;在无图形界面环境下运行图形应用程yum install wqy-zenhei-fonts #…...

【C++】基于多设计模式下的同步异步日志系统

✍作者&#xff1a;阿润021 &#x1f4d6;专栏&#xff1a;C 文章目录 一、项目介绍二、项目实现准备工作1.日志系统技术实现策略2.相关技术知识补充2.1 不定参函数设计2.2 设计模式 三、日志项目框架设计1.模块划分2.各模块关系图 四、详细代码实现1.实用工具类设计2.日志等级…...

防火墙监控工具

防火墙监控是跟踪在高效防火墙性能中起着关键作用的重要防火墙指标&#xff0c;防火墙监控通常应包括&#xff1a; 防火墙日志监控防火墙规则监控防火墙配置监控防火墙警报监控 防火墙监控服务的一个重要方面是它应该是主动的。主动识别内部和外部安全威胁有助于在早期阶段识…...

组合模式——树形结构的处理

1、简介 1.1、概述 树形结构在软件中随处可见&#xff0c;例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形…...

从实体按键看 Android 车载的自定义事件机制

作者&#xff1a;TechMerger 在汽车数字化、智能化变革的进程中&#xff0c;越来越多的车机设计或部分、或全部地舍弃了实体按键&#xff0c;进而把车主操作的入口转移到了车机 UI 以及语音助手。 但统一、高效的零层级 UI 颇为困难&#xff0c;语音的准确率、覆盖率亦不够完善…...

nosql之redis集群

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、redis集群1.单节点redis服务器带来的问题2.集群redis3.集群的优势4.redis集群的实现方法5.redis群集的三种模式5.1 主从复制5.2 哨兵5.3 集群 二、Redis 主从复…...

SpringBoot 项目使用 Redis 对用户 IP 进行接口限流

一、思路 使用接口限流的主要目的在于提高系统的稳定性&#xff0c;防止接口被恶意打击&#xff08;短时间内大量请求&#xff09;。 比如要求某接口在1分钟内请求次数不超过1000次&#xff0c;那么应该如何设计代码呢&#xff1f; 下面讲两种思路&#xff0c;如果想看代码可…...

SLA探活工具EaseProbe

工具介绍 EaseProbe可以做三种工作&#xff1a;探测、通知和报告。 项目地址&#xff1a;https://github.com/megaease/easeprobe 1、安装 [rootlocalhost ]# yum -y install unzip go [rootlocalhost ]# unzip easeprobe-main.zip [rootlocalhost ]# cd easeprobe-main [r…...

[Java] 观察者模式简述

模式定义&#xff1a;定义了对象之间的一对多依赖&#xff0c;让多个观察者对象同时监听某一个主题对象&#xff0c;当主题对象发生变化时&#xff0c;他的所有依赖者都会收到通知并且更新 依照这个图&#xff0c;简单的写一个代码 package Section1.listener;import java.ut…...

linux驱动定时器实现按键按下打印字符

#include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/interrupt.h>struct device_node *dev; unsigned int irqno; //中断处理函数 irqreturn_t myirq_handler(int irq,void *…...

反转链表(JS)

反转链表 题目 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&…...

[PyTorch][chapter 45][RNN_2]

目录&#xff1a; RNN 问题 RNN 时序链问题 RNN 词组预测的例子 RNN简洁实现 一 RNN 问题 RNN 主要有两个问题&#xff0c;梯度弥散和梯度爆炸 1.1 损失函数 梯度 其中&#xff1a; 则 1.1 梯度爆炸&#xff08;Gradient Exploding&#xff09; 上面矩阵进行连乘后…...

基于canvas画布的实用类Fabric.js的使用

目录 前言 一、Fabric.js简介 二、开始 1、引入Fabric.js 2、在main.js中使用 3、初始化画布 三、方法 四、事件 1、常用事件 2、事件绑定 3、事件解绑 五、canvas常用属性 六、对象属性 1、基本属性 2、扩展属性 七、图层层级操作 八、复制和粘贴 1、复制 2…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

Vue ③-生命周期 || 脚手架

生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09; 什么时候可以开始操作dom&#xff1f;&#xff08;至少dom得渲染出来&#xff09; Vue生命周期&#xff1a; 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...