[嵌入式系统-78]:RT-Thread:线程管理的基本原理与应用

目录

一、RTT线程的特点

二、RTT线程机制

 2.1 线程的属性与线程控制块详解

2.2 线程的调度

2.3 线程的切换

2.5 系统线程

三、线程的调度机制

3.1 线程创建与删除

 1、线程控制块

 2、线程栈

3、入口函数

4、线程的创建方式

(1)静态线程初始化函数如下:

(2)动态创建函数如下:

(3)示例1:创建线程

(4)示例2:线程2的代码:

4、线程优先级和Tick

1、线程优先级

2、时间片

5、线程状态

6、空闲线程

四、RTT线程的使用


一、RTT线程的特点

RT Thread(RTT)是一个基于C语言的嵌入式实时操作系统内核,具有方便的API和可裁剪的内核特性。RTT线程管理主要包括线程的创建、销毁、挂起、恢复等功能。通过RTT内核提供的API,可以方便地对线程进行管理和调度,实现任务的实时性和高效性。

RTT线程管理的一些特点包括:

  1. 线程的创建和销毁:可以通过RTT提供的API创建新的线程,并在不需要时销毁线程,以释放系统资源。
  2. 线程的挂起和唤醒:可以通过RTT提供的API将线程挂起(暂停执行),并在需要时唤醒线程(继续执行)。
  3. 线程的优先级调度:RTT支持多种调度算法,可以根据线程的优先级来进行调度,确保高优先级任务优先执行。
  4. 线程同步和通信:通过RTT提供的信号量、邮箱等机制,可以实现线程间的同步和通信,确保数据的正确和实时传输。
  5. 线程的实时性能:RTT线程管理能够保证线程在规定的时间内响应和执行任务,实现实时性能。

总体来说,RTT线程管理通过简洁而高效的API,提供了对线程的灵活管理和调度,帮助开发者实现复杂的实时系统。

RTT线程的一些特点包括:

  1. 实时性能强:RTT线程具有快速响应和执行任务的能力,能够在规定的时间内完成任务。
  2. 高度可裁剪:RTT内核具有可裁剪的特性,可以根据应用需求选择需要的功能和特性,避免系统资源的浪费。
  3. 多任务支持:RTT支持多个任务同时运行,能够根据任务的优先级进行调度,确保高优先级任务先执行。
  4. 足够小巧:RTT内核具有较小的内存占用,适合运行在资源有限的嵌入式系统中。
  5. 灵活的API:RTT提供了简单易用的API,方便开发者进行线程管理和调度。
  6. 精简而高效:RTT线程管理具有高效的执行速度和低延迟,能够满足实时系统的需求。

二、RTT线程机制

 2.1 线程的属性与线程控制块详解

以下是一个简单的RTT线程控制块数据结构的代码示例:

typedef struct rt_thread
{const char *name;           // 线程名称rt_uint8_t priority;        // 线程优先级rt_uint8_t state;           // 线程状态void *stack_addr;           // 线程堆栈地址void *entry;                // 线程入口函数void *parameter;            // 线程参数rt_ubase_t id;              // 线程IDrt_tick_t init_tick;        // 初始时间片rt_tick_t remaining_tick;   // 剩余时间片rt_list_t tList;            // 等待队列
} rt_thread_t;

  1. 线程名称:用于标识线程的名称。
  2. 线程优先级:指定线程的执行优先级。
  3. 线程状态:表示线程当前的状态,如运行、挂起、休眠等。
  4. 线程堆栈:保存线程运行时的栈空间。
  5. 线程入口函数:线程开始执行的入口函数
  6. 线程参数:传递给线程入口函数的参数。
  7. 线程ID:唯一标识线程的ID。
  8. 时间片:指定线程的时间片大小,用于实现多任务调度。
  9. 等待队列:保存等待该线程执行完成的其他线程

        时间片在线程控制块中的作用是指定线程在多任务调度中可以占用的CPU执行时间。时间片值决定了线程执行的时间长度,当时间片用尽后,系统会将 CPU 时间切换到其他同等优先级的可执行的线程,以实现同等优先级多任务并行执行。通过时间片的设置,可以合理分配 CPU 资源,确保系统的实时性和效率。

RT Thread线程的状态通常包括以下几种:

  1. 运行状态:线程当前正在执行,处于运行状态。
  2. 就绪状态:线程已经准备好执行,但由于其他高优先级线程正在执行,暂时无法获得CPU时间片。
  3. 挂起状态:线程被挂起,暂时停止执行,直到恢复为止。
  4. 睡眠状态:线程主动挂起,等待某个条件的发生,如等待定时器超时、事件发生等。
  5. 结束状态:线程执行完毕或被销毁,进入结束状态。

通过这些状态,系统可以动态地管理和调度线程的执行顺序,保证系统的实时性和效率。开发者可以根据需求将线程设置为不同的状态,以实现多任务的并行执行和协同工作。

2.2 线程的调度

RT Thread线程的调度是指系统根据线程的优先级时间片来决定线程的执行顺序和时长。

在RT Thread中,系统会维护一个线程就绪队列,根据线程的优先级来确定每次调度时执行的线程。

当系统启动时,会将优先级最高的就绪线程放到CPU上执行,直到线程执行完毕或时间片用尽,系统会选择下一个优先级最高的就绪线程继续执行。

如果当前线程的优先级低于其他线程的优先级,时间片执行完,系统会暂停当前线程的执行,将CPU时间片分配给更高优先级的线程

时间片是指系统分配给每个线程连续执行的时间长度,当时间片用尽时,系统会进行线程切换,选择另一个就绪线程进行执行。通过动态调度和时间片的控制,系统可以实现多任务的并行执行,提高系统的响应速度和效率。

开发者可以通过设置线程的优先级、时间片等属性来调整线程的调度策略,以满足系统对实时性和性能的需求。合理的线程调度可以帮助系统充分利用CPU资源,提高系统的并发处理能力和稳定性。

2.3 线程的切换

在多任务系统中,线程切换是指从当前正在执行的线程切换到另一个线程的过程。线程切换的原因可能是当前线程时间片用尽、等待I/O操作、等待事件发生等。线程切换的过程包括保存当前线程的上下文信息(包括程序计数器、栈指针、寄存器等)、选择下一个要执行的线程,并将其上下文信息恢复,以便让其继续执行。

在RT Thread中,线程切换是由系统的调度器来控制和执行的。当当前线程的时间片用尽或有更高优先级的线程就绪时,系统会触发线程切换。在线程切换过程中,系统需要保证上下文信息的正确保存和恢复,以确保线程的执行状态能够无缝切换,不影响线程的正常执行。

线程切换是系统调度的关键环节,直接影响系统的响应速度和性能。合理的线程切换策略可以帮助系统高效地分配CPU资源,提高系统的并发处理能力和实时性。开发者可以通过调整线程的优先级、时间片等属性来影响线程切换的频率和方式,以满足系统的需求。

在RT Thread中,抢占式是指系统线程按照其优先级进行调度和执行的方式。当一个高优先级的线程准备就绪并且当前正在运行的线程时间片用尽或主动释放CPU时,系统会立即抢占当前线程的CPU资源,将CPU交给高优先级的线程执行。这种方式能够确保高优先级的任务及时得到执行,提高系统的实时性和响应能力。

在RT Thread中,抢占式调度是通过系统调度器实现的,调度器会根据线程的优先级和就绪状态来决定下一个要执行的线程。开发者可以通过设置线程的优先级来控制线程的调度顺序,确保关键任务能够及时响应和执行。

抢占式调度可以有效避免低优先级任务长时间占用CPU资源而导致系统响应缓慢的情况,提高系统的稳定性和实时性。开发者可以利用RT Thread提供的API接口和工具,合理设计和管理系统线程的优先级和调度策略,以达到系统性能的最优化。

2.5 系统线程

三、线程的调度机制

3.1 线程创建与删除

在RT-Thread中,线程是RT-Thread中最基本的调度单位,使用rt_thread结构体表示线程。

rt_thread描述了一个线程的运行环境,也描述了这个线程所处的优先级

系统中总共有两种线程,分别是系统线程用户线程

  • 系统线程:由RT-Thread内核自己创建
  • 用户线程:由用户应用程序创建

这两类线程都会从内核对象容器中分配线程对象,如下图所示:

每个线程由三部分关键信息组成组成:线程控制块,线程栈和入口函数

 1、线程控制块

线程控制块由结构体rt_thread表示,线程控制块是操作系统用于管理线程的一个数据结构

它存放一些现成的信息,例如线程优先级,线程名称,线程状态等,也包括线程与线程之间连接用的链表结构,线程等待事件集合等

它在rtdef.h中定义:

  1. 线程名称:用于标识线程的名称。
  2. 线程优先级:指定线程的执行优先级。
  3. 线程状态:表示线程当前的状态,如运行、挂起、休眠等。
  4. 线程堆栈:保存线程运行时的栈空间。
  5. 线程入口函数:线程开始执行的入口函数
  6. 线程参数:传递给线程入口函数的参数。
  7. 线程ID:唯一标识线程的ID。
  8. 时间片:指定线程的时间片大小,用于实现多任务调度。
  9. 等待队列:保存等待该线程执行完成的其他线程

 2、线程栈

在裸机系统中,涉及局部变量、子函数调用或中断发生,就需要用到栈,

而在RTOS系统中,每个线程运行时,也是普通函数调用,也涉及局部变量、子函数调用、中断,也要用到栈。

但不同于裸机系统,RTOS存在多个线程,每个线程互不干扰的,因此需要为每个线程都分配独立的栈空间,这就是线程栈。

在RT Thread中,每个线程都有自己的栈空间用于存储局部变量、函数调用信息和临时数据。线程栈在 struct rt_thread 的成员中包含了 stack_addr stack_size 两个属性,分别表示线程的栈地址和栈大小。

线程栈的大小是一个重要的考虑因素,它需要根据线程的任务需求和系统资源进行合理设置。如果线程执行过程中需要使用大量的局部变量或进行复杂的函数调用,那么需要分配足够大的栈空间来避免栈溢出的情况发生

在创建线程时,开发者需要指定线程的 stack_addr 和 stack_size,系统会根据这两个参数来为线程分配合适的栈空间。通过合理设置线程栈的大小和地址,可以有效地优化系统内存的利用并避免因栈溢出而导致的系统崩溃问题。

总之,线程栈在RT Thread中扮演着重要的角色,通过合理管理线程栈的大小和地址,可以确保系统线程的正常运行和稳定性。

3、入口函数

入口函数是线程要运行的函数,由用户自行设计。

可分为无限循环模式和顺序执行模式

void thread_entry(void *parameter)
{
    while(1)
    {
        /*等待事件发生*/
        /*对事件进行服务,进行处理*/
    }
 
 
}
使用这种模式时,需要注意,一个实时操作系统,不应该让一个线程一直处于最高优先级占用CPU,让其他线程得不到执行。

因此在这种模式下,需要调用延时函数或者主动挂起。这种无限循环模式设计的目的是让这个线程一直循环调度运行,而不结束。

顺序执行模式

static void thread_entry(void *parameter)
{
    /*处理事务1*/
    ...
    /*处理事务2*/
    ...
    /*处理事务3*/
}
使用这种模式时线程不会一直循环,最后一定会执行完毕。

执行完毕之后,线程将被系统自动删除。

以上就是线程的三要素:线程控制块,线程栈,入口函数;

线程的五种状态:初始态,就绪态,运行态,挂起态,关闭态。

线程的三种基本形式:单次执行,周期执行,资源驱动(时间也是资源的一种)

4、线程的创建方式

RT-Thread提供两种线程的创建方式:

  • 静态创建:使用rt_thread_init(void *parameter)
  • 动态创建:使用rt_thread_creare(void *paremeter)

这两种方式的区别就是分配线程控制块和线程栈的分配方式是静态的还是动态的。

静态线程:由使用该API的用户来分配栈空间线程句柄的内存。

动态线程:是系统(API函数内部)自动从动态内存堆上分配栈线程的堆栈空间与线程句柄以及对应的线程控制块的内存。

(1)静态线程初始化函数如下:

(2)动态创建函数如下:

动态模式:不需要用户指定现场堆栈的空间地址。

创建线程后,还需要启动线程,才能让线程运行起来。

启动线程函数如下:

rt_err_t rt_thread_startup(rt_thread_t thread)

(3)启动线程

(3)示例1:创建线程

使用静态创建和动态创建两种方法分别创建两个线程

线程1的代码:

/*线程1的入口函数*/
static void thread1_entry(void *parameter)
{
 
    const char *thread_name = "Thread1_run\r\n";
    volatile rt_uint32_t cnt = 0;
    
 
    /*线程1*/
    while(1)
    {
        /*打印线程1的信息*/
        rt_kprintf(thread_name);
 
        /*延迟一会(比较简单粗暴)*/
        for(cnt=0;cnt<100000;cnt++)
        {
 
        }
    }
 
}

(4)示例2:线程2的代码:
 

/*线程2入口函数*/
static void thread_entry(void *parametr)
{
    const char *thread_name = "Thread2 run";
    volatile rt_uint32_t cnt = 0;
    
    /*线程2*/
 
    while(1)
    {
        /*打印线程2的信息*/
        rt_kprintf(thread_name);
 
    }
 
    /*延迟一会,简单粗暴*/
    for(cnt = 0;cnt<100000;cnt++)
    {
    
    }
 
}

 静态创建线程:

rt_thread_init(&thread1,            //线程句柄
                "thread1"            //线程名字
                thread1_entry,        //入口函数
                RT_NULL,               //入口函数参数
                &thread1_stack[0],    //线程栈起始地址
                sizeof(thread1_stack),    //栈大小
                THREAD_PRIORITY,        //线程优先级
                THREAD_TIMESLICE        //线程时间片大小
 
                );
 
rt_thread_startup(&thread1);
动态创建线程:

thread2 = rt_thread_create("thread2",        //线程名字
                            thread2_entry,        //入口函数
                            RT_NULL,                //入口函数参数
                            THREAD__STACK_SIZE,    //栈大小
                            THREAD_PRIORITY,        //线程优先级
                            THREAD_TIMESLICE        //线程时间片
                            )

4、线程优先级和Tick

1、线程优先级

RT-Thread的线程优先级是指线程被调度的优先程度

每个线程都有优先级,线程的重要性越高,优先级应该设置的越高,被调度的可能才会更大。

由rtconfig.h中定义的RT_THREAD_PRIORITY宏指定优先级范围,RT-Thread最大支持256级优先级,数值越小的优先级越高,0为最高优先级。

在学习调度方法之前,只要粗略的知道,RT-Thread会确保优先级最高,可运行的线程,马上就能执行。

RT-Thread会确保优先级最高的,可运行的线程马上就能执行。

对于相同优先级的,可运行的线程,轮流执行。

举个例子,

厨房着火了,当然优先灭火

喂饭,回复信息同样重要,轮流做

2、时间片

RT-Thread中也有心跳,它使定时器产生固定间隔的中断,这叫Tick,滴答,比如每1ms发生一次时钟中断。

5、线程状态

简单分为运行态和非运行态,具体的非运行态又可以细分,

初始态(RT_THREAD_INIT):创建线程的时候会将线程的状态设置为初始态

就绪态(RT_THREAD_READY):该线程就在就绪列表中,就绪的线程已经具备执行的能力,只等待CPU

运行态(RT_THREAD_RUNNING):该线程正在运行,此时它正占用CPU

挂起态(RT_THREAD_SUSPEND):如果线程当前正在等待某个时序或外部中断,我们就说这个线程处于挂起状态,该线程不在就绪列表中,包含线程被挂起、线程被延时,线程正在等待信号量、读写队列或者等待读写事件

关闭态(RT_THREAD_CL):该线程运行结束,等待系统回收资源。

线程状态迁移

RT_Thread系统中的每一个线程都有多种运行状态,他们之间的转换关系如下图所示,从运行态变成阻塞态、或者从阻塞态变成就绪态,这些线程状态是怎么迁移的呢?

6、空闲线程

空闲线程是系统中一个比较特殊的线程,它具有最低的优先级,当系统中无其他线程可运行时,调度器将调度到空闲线程。空闲线程通常是一个死循环,永远不挂起。

RT_Thread实时操作系统为空闲线程提供了一个钩子函数(钩子函数:用户提供的一段代码,在系统运行的某一路径上设置一个钩子,当系统经过这个位置时,转而执行这个钩子函数,然后再返回到它的正常路径上) ,可以让系统在空闲的时候执行一些特定的任务,例如系统运行指示灯闪烁,电源管理等,除了调用钩子函数,RT_Thread也把线程清理(rt_thread_cleanup)函数,真正的线程删除动作放到了空闲线程中(在删除线程时,仅改变线程的状态为关闭状态不在参与系统调度)。

调度器相关接口

调度器初始化

在系统启动时需要执行调度器的初始化,以初始化系统调度器用到的一些全局变量。调度器初始化可以调用下面的接口:

void rt_system_schduler_init(void)

启动调度器

void rt_system_scheduler(void)

执行调度

void rt_schedule(void)

设置调度器钩子函数

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

void rt_scheduler_sethook(void (*hook)(struct rt_thread* from,struct rt_thread* to))

四、RTT线程的使用

RTT线程管理提供了一系列API函数,用于线程的创建、销毁、挂起、唤醒等操作。

一些常用的线程相关API函数包括:

  1. rt_thread_t rt_thread_create(const char* name, rt_thread_entry_t entry, void* parameter, rt_uint32_t stack_size, rt_uint8_t priority, rt_uint32_t tick):
    创建一个新的线程,指定线程的名称、入口函数、参数、栈空间大小、优先级和指定时间片长度等参数。

  2. void rt_thread_delete(rt_thread_t thread):
    销毁指定的线程,释放线程占用的资源。

  3. rt_err_t rt_thread_startup(rt_thread_t thread):
    启动指定的线程,使其开始执行任务。

  4. void rt_thread_yield(void):
    主动让出CPU执行时间,从当前线程切换到其他可执行的线程执行。

  5. rt_err_t rt_thread_suspend(rt_thread_t thread):
    挂起指定的线程,暂停其执行。

  6. rt_err_t rt_thread_resume(rt_thread_t thread):
    恢复指定的线程,使其继续执行。

  7. rt_err_t rt_thread_sleep(rt_tick_t tick):
    使当前线程休眠指定的时钟节拍数

  8. rt_err_t rt_thread_delay(rt_tick_t tick):
    使当前线程延迟指定的时钟节拍数后执行。

以上是一些RTT线程相关的常用API函数,开发者可以根据需求选择合适的API函数来管理和调度线程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/11764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【手势操作-复习前一天的内容-预习今天的内容 Objective-C语言】

一、昨天呢,我们学习的是这个,事件 1.事件这一块儿呢,iOS事件,分为三大类, 1)触摸事件 2)加速计事件 3)远程控制事件 2.这个里边呢,我们主要学习的是这个触摸事件,触摸事件里边,就是Touch,touchesBegan:方法里边,有一个touches参数,它是set类型的, 3.Set,…

Redis:分布式系统

文章目录 认识RedisRedis和MySQLRedis的场景Redis的设计 分布式单机架构应用数据分离架构应用服务集群架构 认识Redis 在开始Redis学习前&#xff0c;要先认识一下Redis Redis的设计&#xff0c;是想要把它当做是一个数据库&#xff0c;一个缓存&#xff0c;或者说是一个消息…

C语言 | Leetcode C语言题解之第87题扰乱字符串

题目&#xff1a; 题解&#xff1a; struct HashTable {int key;int val;UT_hash_handle hh; };void modifyHashTable(struct HashTable** hashTable, int x, int inc) {struct HashTable* tmp;HASH_FIND_INT(*hashTable, &x, tmp);if (tmp NULL) {tmp malloc(sizeof(st…

Nginx - location中的匹配规则和动态Proxy

文章目录 官网location 规则详解动态Proxy使用多个 if 指令指定不同的 proxy_pass根据参数选择不同的 proxy_pass 官网 https://nginx.org/en/docs/http/ngx_http_core_module.html#location location 规则详解 Nginx的location指令工作原理如下&#xff1a; 位置匹配&#…

vs2019 c++ 对左值引用取地址得到的是谁的地址?

&#xff08;1&#xff09; 测试一下&#xff1a; 对左值引用取地址&#xff0c;返回的地址是其引用的变量的地址&#xff0c;而非自身的地址。 &#xff08;2&#xff09; 用反汇编看一下&#xff0c;为了代码容易看懂&#xff0c;改一下源代码&#xff0c;不使用 cout 这个复…

【格式控制】(中北大学-程序设计基础(2))

目录 题目 源码 结果示例 题目 从键盘输入一批数值&#xff0c;要求保留3位小数&#xff0c;在输出时上下行小数点对齐。 源码 #include <iostream>using namespace std;int main(void) {double a, b, c;cout << "请输入三个实数&#xff0c;中间用空格…

阿里云OSS配置跨域及域名访问

1、配置跨域 进入对象存储OSS–>OSS存储桶–>数据安全–>跨域设置–>创建规则 2、配置跨域 Etag x-oss-request-id3、配置结果如下 4、数据源配置 切换到数据管理–>静态页面 配置根页面 保存结果如下 5、配置域名访问 绑定域名 添加txt记录 验证绑定 …

git仓库使用

git仓库是会限制空间大小限制的 git网络库的容量限制_github仓库大小限制-CSDN博客 git是用于管理github的工具 电脑左下角搜索git打开GitBash.exe 进入到要下载到本地的目录 下载到本地的文件不要更改&#xff01; 如果要使用请务必把文件复制到别的空间去再在这个别的空间…

论文阅读记录--关于水文系统的传递函数

文章目录 J-schuite的文章,地下水系统的响应的功率谱分析--传递函数1. 什么是冲激响应函数与传递函数?2. 地下水流系统中传递函数的求解3. J-schuite文章中传递函数的复现J-schuite的文章,地下水系统的响应的功率谱分析–传递函数 1. 什么是冲激响应函数与传递函数? 在信号…

社交媒体数据恢复:华为畅连

尊敬的用户您好&#xff0c;以下是关于社交软件华为畅连的聊天记录数据恢复教程。在华为手机中&#xff0c;我们可以通过华为云服务和第三方软件来恢复删除的聊天记录。以下是详细的步骤&#xff1a; 第一步&#xff1a;登录华为云服务 请在您的华为手机上找到并打开“云服务”…

网络编程:服务器模型-并发服务器-多进程

并发服务器概念&#xff1a; 并发服务器同一时刻可以处理多个客户机的请求 设计思路&#xff1a; 并发服务器是在循环服务器基础上优化过来的 &#xff08;1&#xff09;每连接一个客户机&#xff0c;服务器立马创建子进程或者子线程来跟新的客户机通信 &#xff08;accept之后…

SpringBoot报空指针错:java.lang.NullPointerException

虽然报空指针错误的原因可能有很多种&#xff0c;但是我还是写上我的报错原因&#xff0c;以此与各位共勉~ 在这里提前说一句&#xff0c;AI虽然强大&#xff0c;但是还是要谨慎使用啊(血的教训)~ 这里先截图我错误的地方&#xff1a; 前端能成功传进来值&#xff0c;后台控制…

图像质量评价指标:了解图像质量的度量方式

图像质量评价指标&#xff1a;了解图像质量的度量方式 在图像处理和计算机视觉领域&#xff0c;评价图像质量的准确性对于许多应用至关重要。通过合适的评价指标&#xff0c;我们可以量化图像的质量&#xff0c;从而更好地了解图像处理算法的效果和改进空间。本文将介绍图像质…

英语学习笔记12——名词所有格的运用

Whose is this … ? This is my/your/his/her … 这……是谁的&#xff1f;这是我的 / 你的 / 他的 / 她的…… Whose is that … ? That is my/your/his/her … 那……是谁的&#xff1f;那是我的 / 你的 / 他的 / 她的…… 词汇 Vocabulary father n. 爸爸 口语&#xf…

2024统计建模成品论文39页(附带完整数据集和代码)

2024统计建模成品论文完整版一等奖论文【1.5w字全网最佳】2024统计建模大赛高质量成品论文39页配套完整代码运行全套数据集https://www.jdmm.cc/file/2710661/

在idea中使用vue

一、安装node.js 1、在node.js官网&#xff08;下载 | Node.js 中文网&#xff09;上下载适合自己电脑版本的node.js压缩包 2、下载完成后进行解压并安装&#xff0c;一定要记住自己的安装路径 一直点击next即可&#xff0c;这部选第一个 3、安装成功后&#xff0c;按住winR输入…

如何使用 ArcGIS Pro 计算容积率

容积率是指地上建筑物的总面积与用地面积的比率&#xff0c;数值越小越舒适&#xff0c;这里为大家介绍一下如何使用ArcGIS Pro 计算容积率&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的建筑和小区数据&#xff0c;除了建筑和小区数据&am…

【408精华知识】速看!各种排序的大总结!

文章目录 一、插入排序&#xff08;一&#xff09;直接插入排序&#xff08;二&#xff09;折半插入排序&#xff08;三&#xff09;希尔排序 二、交换排序&#xff08;一&#xff09;冒泡排序&#xff08;二&#xff09;快速排序 三、选择排序&#xff08;一&#xff09;简单选…

【Arduino】数字I/O的使用

目录 1、引脚工作模式 2、写入引脚digitaWrite&#xff08;&#xff09; 3、读取引脚digitalRead(pin); 4、示例 跑马灯 1、引脚工作模式 Arduino通过pinMode()设置引脚的io工作模式&#xff0c;一共有4种模式 工作模式 Mode 说明 输出模式 OUTPUT 引脚为低阻抗状态&…

YOLOv9改进策略目录 | 包含卷积、主干、检测头、注意力机制、Neck上百种创新机制

&#x1f451; YOLOv9有效涨点专栏目录 &#x1f451; 专栏视频介绍&#xff1a;包括专栏介绍、得到的项目文件、模型二次创新、权重文件的使用问题&#xff0c;点击即可跳转。 前言 Hello&#xff0c;各位读者们好 本专栏自开设两个月以来已经更新改进教程50余篇其中包含Re…