RT_Thread内核源码分析(一)——CM3内核和上下文切换

news2024/11/17 10:24:51

       

目录

一、程序存储分析

1.1  CM3内核寻址空间映射

1.2  程序静态存储和动态执行

二、CM3内核相关知识

2.1 操作模式和特权极别

2.2 环境相关寄存器

2.2.1  通用寄存器组,

2.2.2  状态寄存器组

2.2.3  模式切换环境自动保存

2.2.4  函数调用形参位置

2.3 中断

2.3.1  PendSV(可悬起软中断)

2.3.2 SysTick(系统定时器),

三、RT_Thread线程结构

四、RT_Thread启动分析

五、RT_Thread上线文切换

5.1 上下文切换本质

5.2 上下文切换场景

5.3 上下文切换源码实现

5.3.1 启动第一个线程

5.3.2 调度中上下文切换

5.3.3 上下文切换源码分析

5.3.4 上下文切换逻辑图

5.4 上下文切换实例分析


        对于实时操作系统来说,上下文切换是线程抢占或轮询的根本,要想吃透操作系统,必需先搞明白上下文切换的过程,若要搞明白上线文切换,必然少不了与CPU内核打交道,本文基于STM32F10X系列单片机( 内核为Cortex-M3核,简称CM3),讲解RT_Thread Nano实时操作系统的上下文切换。

本章基于RT_Thread Nano V3.1.5版本分析

本章基于Cortex-M3内核和Keil5编译器分析,详细内核知识参考《CM3权威指南CnR2 宋岩 译》

一、程序存储分析

1.1  CM3内核寻址空间映射

        如下图所示:

        对于STM32F103ZE型号的单片机,Code区采用容量为512kB总线接口的NorFlash;SRAM区为64kB的SRAM存储器,暂不考虑扩展SRAM。

1.2  程序静态存储和动态执行

        使用keil5编译STM32程序后,程序存储分析如下图所示:

        各存储区说明:

存储区

属性

存储位置

运行位置

存储内容

CODE

只读

NorFlash

NorFlash

代码区:所有程序指令。

(起始为MSP初始化值+Reset向量)

RO-DATA

只读

NorFlash

NorFlash

常量区:const修饰的常量、字符串。

RW-DATA

读/写

NorFlash

SRAM

变量区:初始化为非0的全局、静态变量。

ZI-DATA

变量区

读/写

SRAM

(运行中分配)

变量区:未初始化和初始化为0的全局、静态变量。

heap

读/写

SRAM

(运行中分配)

堆区:使用编译器微库,用于malloc申请动态内存。

stack

读/写

SRAM

(运行中分配)

栈区:特权级线程(Thread)、中断(异常)模式的局部变量。

(1)单片机内部FLASH启动模式下,ICode总线只能从NorFLASH取指令,代码段只能在NorFlash运行。

(2)总线接口的NorFlash可以用作只读内存,RO-DATA(只读数据)可以不搬移至内存。

(2)heap段使用需要启动keil的微库,才能通过malloc等操作进行动态内存申请,操作系统可以使用该方式分配总的动态内存区,但不要使用该方式分配任务栈,任务栈申请使用操作系统自带的方式。

(3)stack段默认给特权级线程、中断(异常)模式使用,由MSP寄存器控制出入栈,如果切换到用户模式,自动切换为进程栈指针寄存器(PSP),用户模式需要重新申请栈区,PSP指向用户栈区;操作系统中的动态内存区可以根据需求设置在RW-DATA段、ZI-DATA堆区、ZI-DATA变量区。

(4)ZI-DATA区:该类变量初始值全为0,故不体现在静态存储中,在运行态由指令进行内存分配,分配代码由Keil编译器自动生成,我们只需要在工程配置和启动文件中将存储器参数和堆栈申请空间配置好就行,如下所示:

        Keil编译器存储器设置NorFLASH、SRAM:

        启动文件(.s)中主程序堆(heap)空间分配:

        启动文件(.s)中主程序栈(stack)空间分配:

        编译结果:

        Map文件查看:

二、CM3内核相关知识

2.1 操作模式和特权极别

  1. CM3有2种操作模式: 处理者模式(或中断(异常)模式 handler mode )、线程(Thread mode)模式
  2. CM3有2种权利级别: 特权级、用户级,特权级使用MSP栈指针寄存器,用户级使用PSP栈指针寄存器。两种级别的栈相互独立。
  3. 处理者模式(handler mode)只能运行在特权级别。
  4. 用户级对系统控制空间(SCS)的访问将被阻止——该空间包含了配置寄存器组以及调试组件的寄存器组。还禁止使用 MRS/MSR 访问,除了 APSR 之外的特殊功能寄存器。如果以身试法,则对于访问特殊功能寄存器的,访问操作被忽略;而对于访问 SCS 空间的,将触发fault异常。
  5. 软件触发中断寄存器可以在用户级下访问以产生软件中断(利用这个特性实现用户模式到特权模式转变)。

        各种模式之间的切换:

模式切换

触发条件

栈指针

特权级Thread 模式

上电启动

MSP

特权级Thread 模式->特权级handler模式

中断、异常触发

R14(LD)更新为0XFFFFFFF9

MSP

特权级Thread 模式->用户级Thread 模式

操作寄存器CONTROL[0]置1

MSP切换为PSP

特权级handler模式->特权级Thread 模式

调用指令“BX R14”

其中R14=0XFFFFFFF9

MSP

特权级handler模式->用户级Thread 模式

调用指令“BX R14”

其中R14=0XFFFFFFFD

MSP切换为PSP

用户级Thread 模式->特权级handler模式

中断、异常触发

R14更新为0XFFFFFFFD

PSP切换为MSP

用户级Thread 模式->特权级Thread 模式

主动触发异常(SVCall异常)

调用指令“BX R14”返回异常

其中R14=0XFFFFFFF9

PSP切换为MSP

2.2 环境相关寄存器

        CM3用于上下文切换的寄存器主要包括通用寄存器组、状态寄存器组。

2.2.1  通用寄存器组,

        如下图所示:

(1)通用寄存器

        R0-R12 都是 32 位通用寄存器,用于数据操作、暂存。绝大多数 16 位 Thumb 指令只能访问 R0-R7,而 32 位 Thumb-2 指令可以访问所有寄存器。

(2)堆栈指针(SP)

        R13用于栈指针(SP),指向栈区(stack),通过入栈出栈分配和释放临时变量。比如一个函数中定义了一些临时变量,调整SP指针(入栈)分配临时变量的存储空间,函数返回时,调整SP指针(出栈)释放掉堆栈空间,所以临时变量初始值是个不确定的值,因为出栈仅是调整SP指针,并不对栈空间进行归零等操作,且临时变量不宜过多,防止栈空间溢出。

        CM3内核拥有两个堆栈指针:

        主堆栈指针(MSP:特权级别下使用,复位后缺省使用的堆栈指针,初始值指向内存ZI-DATA栈区(Stack)的栈底(一般是高地址),代码区第一条指令就是MSP的初始化值,装置上电会先更新MSP,然后在执行reset。

        进程堆栈指针(PSP:用户级别下使用,在操作系统中,指向任务的栈区,任务栈区一般从操作系统动态内存区分配,操作系统动态内存区可以根据可以根据需求设置在RW-DATA段、ZI-DATA堆区、ZI-DATA变量区。

(3)连接寄存器(LD)

        R14用作连接寄存器(LD),连接寄存器当调用一个子程序时,R14存储指令返回地址,如果只有 1 级子程序调用的代码无需访问内存(堆栈内存),从而提高了子程序调用的效率。如果多于 1 级,则需要把前一级的 R14 值压到堆栈里。

        程序进入handler模式(中断(异常))时,R14自动入栈保存,保存后R14更新为0xFFFFFFFX,通过指令”BX  R14”进行异常返回。X的bit0为1表示返回thumb状态,bit1和bit2表示返回后sp用msp还是psp及返回到特权级别还是用户级别。合法的返回值如下所示:

0xFFFF_FFF1返回handler模式【应用于中断嵌套的场景】
0xFFFF_FFF9返回线程模式,并使用主堆栈(SP=MSP)【返回特权级线程(Thread)模式】
0xFFFF_FFFD返回线程模式,并使用线程堆栈(SP=PSP)【返回用户级线程(Thread)模式】

(4) 程序计数寄存器(PC)

        R15用作程序计数寄存器(PC),程序计数寄存器指向NorFLASH代码区。正常运行,取指令完成,PC自动加1,既PC指向下一条指令,如果执行跳转指令或者直接修改PC寄存器的值, 就能改变程序的执行流。

2.2.2  状态寄存器组

        状态字寄存器组包括:应用程序 PSR(APSR)、 中断号 PSR(IPSR)、执行 PSR(EPSR),环境保存时是三个寄存器会合并为一个32位xPSR进行保存。

2.2.3  模式切换环境自动保存

        与一些高端内核不同,CM3由线程模式(Thread)进入handler模式会自动进行部分寄存器的入栈保存,下图参考自《CM3权威指南CnR2 宋岩 译》:

2.2.4  函数调用形参位置

        ARM系列平台,函数形参按从左向右顺序存放在寄存器r0,r1,r2,r3里,超过4个参数值传递则放栈里。

        比如函数:

void test(int iv1,int iv2,int iv3,int iv4,int iv5,int iv6);

        形参:iv1、iv2、iv3、iv4分别存入寄存器r0、r1、r2、r3进行传递。

        形参:iv5、iv6则入栈传递。

2.3 中断

        RT_Thread操作系统调度器涉及CM3的2个中断,PendSV用于上下文切换,SysTick提供时间片,如下图:

2.3.1  PendSV(可悬起软中断)

       该中断可以在高优先级中断(异常)中设置为悬起,等所有高优先级中断返回后,再执行PendSV,俗称“缓期执行”,所以PendSV的优先级一般会设置为最低。

        也可以在用户级或特权级线程模式调用该服务进入handler模式。

        在操作系统中,用于上下文切换,悬起 PendSV 的方法是:手工往 NVIC 的 PendSV 悬起寄存器中写 1。

2.3.2 SysTick(系统定时器),

        可编程的定时中断(自检),为操作系统提供时间片,进行轮询和抢占式调度。设置方法可以参考《CM3权威指南CnR2 宋岩 译》。

三、RT_Thread线程结构

        RT_Thread操作系统每个线程有独立的线程控制块(TCB)和线程栈,线程栈主要用于分配临时变量,在线程切换和初始化时,存储线程环境(通用寄存器+状态寄存器),寄存器排列顺序固定,如下图所示,可分为自动出入栈部分和手动出入栈部分,自动出入栈部分在CM3内核模式切换时由硬件自动实现(见2.2.3章节),手动出入栈部分则需要上下文切换代码实现。

四、RT_Thread启动分析

        在分析操作系统上下文切换之前,先从宏观上分析操作系统启动和运行的过程。

(1)程序运行先进入特权级Thread模式,系统初始化完成后,取最高优先级线程作为第一个线程运行,执行启动第一个线程接口,触发PendSv中断,进入特权级Handler模式,寄存器LD强制为0XFFFFFFF9;执行上下文切换代码,将第一个线程中的环境(通用寄存器组+状态寄存器组)出栈,并通过执行BX 0XFFFFFFFD,跳转到用户级线程模式执行第一个线程的代码,此时使用的堆栈指针为PSP,指向第一个线程的线程栈。

(2)启动第一个线程接口同时会启动时间片中断(SysTick),为操作系统提供心跳和定时器周期轮询线程的功能,这样操作系统正常运行。

(3)由图中可以看出,操作系统正常运行后,只在用户级Thread模式和特权级Handler模式之间切换,如果不出现异常是不会在返回特权级Thread模式的。

五、RT_Thread上线文切换

5.1 上下文切换本质

        RT_Thread操作系统进行上下文切换方法是挂起PendSv中断,在中断中将线程模式下的寄存器(通用寄存器+状态寄存器)入栈到当前线程栈,从另一线程(高优先级)的线程栈中出栈环境保存的寄存器数值,然后恢复到线程模式;本质是保存和切换寄器(通用寄存器+状态寄存器)数值。

5.2 上下文切换场景

        RT_Thread操作系统支持抢占式调度,在线程运行过程中会涉及到上下文切换,其场景可分为2类:

被动切换:当有更高优先级线程就绪时,调度器强制将当前线程寄存器状态入栈,将高优先级线程寄存器状态出栈,实现任务切换;此过程一般在定时器线程或SysTick中断中触发

主动切换:当前任务主动进入阻塞(vTaskDelay)、接收消息阻塞、接收信号阻塞、释放新线程等;会主动触发上下文切换。

5.3 上下文切换源码实现

        上下文切换接口和相关变量如下所示:

// 相关函数接口

/************【1】启动第一个线程********************************************/
void rt_hw_context_switch_to(rt_ubase_t to);
/************【2】线程中上线文切花*******************************************/
void rt_hw_context_switch(rt_ubase_t from, rt_ubase_t to);
/************【3】中断中上下文切换*******************************************/
void rt_hw_context_switch_interrupt(rt_ubase_t from, rt_ubase_t to);

// 相关变量
rt_uint32_t rt_interrupt_from_thread;         // 指向原线程栈顶指针
rt_uint32_t rt_interrupt_to_thread;           // 指向目的线程栈栈顶指针
rt_uint32_t rt_thread_switch_interrupt_flag;  // 上线文正在切换中标志

5.3.1 启动第一个线程

        操作系统启动时会选择最高优先级的线程作为第一个线程启动,调用方式如下,形参为线程的栈顶指针地址,根据2.2.4章节描述,CM3内核会自动使用R0寄存器传递形参(rt_uint32_t)&to_thread->sp。

rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);

        第一个线程汇编启动接口如下所示,设置好目的线程rt_interrupt_to_thread和上下文切换标志rt_thread_switch_interrupt_flag后,触发PendSv中断,在PendSv中断中执行上下文切换。

;函数声明
rt_hw_context_switch_to    PROC
EXPORT rt_hw_context_switch_to
 
   ;【1】目的线程rt_interrupt_to_thread指向启动线程栈指针,即(rt_uint32_t)&to_thread->sp
    LDR     r1, =rt_interrupt_to_thread
    STR     r0, [r1]
   ;【2】原线程rt_interrupt_from_thread指向空,设置为0
    LDR     r1, =rt_interrupt_from_thread               
    MOV     r0, #0x0
    STR     r0, [r1]
    ;【3】上下文切换标志rt_thread_switch_interrupt_flag 设置为1
    LDR     r1, =rt_thread_switch_interrupt_flag    
    MOV     r0, #1
    STR     r0, [r1]
    ;【4】设置中断PendSV和中断SysTick优先级
    LDR     r0, =NVIC_SYSPRI2 
    LDR     r1, =NVIC_PENDSV_PRI
    LDR.W   r2, [r0,#0x00]                            ; read
    ORR     r1,r1,r2                                  ; modify
    STR     r1, [r0]                                  ; write-back

    ;【5】挂起PendSv (上下文切换)
    LDR     r0, =NVIC_INT_CTRL                          
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]

    ;【6】恢复 MSP
    LDR     r0, =SCB_VTOR                                    
    LDR     r0, [r0]
    LDR     r0, [r0]
    MSR     msp, r0

   ;【6】在处理器级别启用中断,中断启用后,由于PendSv中断已经挂起,代码会跳转到PendsV中断执行
    CPSIE   F                                                        
    CPSIE   I

    ;【7】跳转PendsV中断后,系统在用户级Thread模式和特权级handler模式间切换,永远运行不到此处!
    ENDP                                                            

5.3.2 调度中上下文切换

        操作系统调度正常运行后,时间片中断或线程可能会启动上下文切换,调用接口函数如下所示,根据2.2.4章节描述,CM3内核会自动使用R0寄存器传递形参(rt_uint32_t)&from_thread->sp,R1寄存器传递形参(rt_uint32_t)&to_thread->sp。

 rt_hw_context_switch((rt_ubase_t)&from_thread->sp, (rt_ubase_t)&to_thread->sp);
 rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp, (rt_ubase_t)&to_thread->sp);

         2种函数汇编代码虽然相同,但是内核模式不同,线程中执行接口是在用户级Thread模式,而时间片中断执行接口,是在特权级Handler模式。

        执行接口之前均对高优先级中断进行了屏蔽,所以,以下汇编执行过程不会中断。

       汇编启动接口如下所示, 设置好如下参数,

                rt_uint32_t rt_interrupt_from_thread;            // 原线程栈指针
                rt_uint32_t rt_interrupt_to_thread;                // 目的线程栈指针
                rt_uint32_t rt_thread_switch_interrupt_flag;  // 上线文正在切换中标志

        触发PendSv中断,在PendSv中断中执行上下文切换。

rt_hw_context_switch_interrupt
    EXPORT rt_hw_context_switch_interrupt
rt_hw_context_switch    PROC
    EXPORT rt_hw_context_switch

    ;【1】上下文切换标志rt_thread_switch_interrupt_flag判断
    LDR     r2, =rt_thread_switch_interrupt_flag
    LDR     r3, [r2]
    ;【1.1】上下文切换标志rt_thread_switch_interrupt_flag为1,跳至_reswitch 
    CMP     r3, #1
    BEQ     _reswitch                                     
    ;【1.2】上下文切换标志rt_thread_switch_interrupt_flag不为1,赋值为1
    MOV     r3, #1
    STR     r3, [r2]                                             
    ;【2】rt_interrupt_from_thread 指向源线程栈指针
    LDR     r2, =rt_interrupt_from_thread
    STR     r0, [r2]
_reswitch
    ;【3】rt_interrupt_to_thread指向目标线程栈指针
    LDR     r2, =rt_interrupt_to_thread 
    STR     r1, [r2]
    ;【4】触发PendSv异常(进行上下文切换)
    LDR     r0, =NVIC_INT_CTRL 
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]
    ;【5】跳出
    BX      LR
    ENDP

5.3.3 上下文切换源码分析

        从5.3.1章节5.3.2章节可见,不管是启动第一个线程还是系统运行中线程切换,最终执行的位置是PendSv中断,并且在执行中断前,已经通过全局变量传输参数。

        rt_uint32_t rt_interrupt_from_thread;            // 原线程栈指针
        rt_uint32_t rt_interrupt_to_thread;                // 目的线程栈指针
        rt_uint32_t rt_thread_switch_interrupt_flag;  // 上线文正在切换中标志

        如果是启动第一个线程,CM3内核会从特权级Thread模式进入特权级Handler模式,R14数值更新为0XFFFFFFF9,执行完上下文切换后, R14数值更新为0XFFFFFFFD,通过指令BX 0xFFFFFFFD返回到用户级Thread模式。

         如果,操作系统调度启动后,线程中进行上下文切换,会先屏蔽中断,再挂起PendSv,等恢复中断后,PendSv才能响应,CM3内核会从特权级Thread模式进入特权级Handler模式,R14数值更新为0XFFFFFFFD;寄存器R0、R1、R2、R3、R12、R14(LR)、R15(PC)、XPSR
自动通过指针PSP入栈,堆栈指针切换为MSP。

         如果,时间片执行上下文切换,等时间片中断完全执行完成后,才能响应PendSv中断。

        上下文切换汇编源码分析如下:

PendSV_Handler   PROC
EXPORT PendSV_Handler
    ; 【0.1】如果用户级线程模式进入中断,R0、R1、R2、R3、R12、R14(LR)、R15(PC)、XPSR
    ;  自动通过指针PSP入栈,堆栈指针切换为MSP,
    ; 【1】屏蔽除NMI和Fault外的中断
    MRS     r2, PRIMASK      ;中断屏蔽寄存器PRIMASK暂存,用于恢复
    CPSID   I                ;屏蔽除NMI和Fault中断
    ; 【2】判断上下文切换标志标志rt_thread_switch_interrupt_flag
    LDR     r0, =rt_thread_switch_interrupt_flag  
    LDR     r1, [r0]            
    ; 【2.1】上下文切换未进行,正常切换,否则执行pendsv_exit,退出切换                                              
    CBZ     r1, pendsv_exit                                            
    ; 【3】清除上下文切换标志标志rt_thread_switch_interrupt_flag
    MOV     r1, #0x00 
    STR     r1, [r0] 
    ; 【4】判断原线程rt_interrupt_from_thread,
    LDR     r0, =rt_interrupt_from_thread                      			 
    LDR     r1, [r0]
    ; 【4.1】原线程rt_interrupt_from_thread无效,跳至switch_to_thread,直接恢复目的线程
    CBZ     r1, switch_to_thread 
    ; 【4.2】原线程rt_interrupt_from_thread有效,对原线程进行环境保存
    MRS     r1, psp            ;R1用作原线程栈指针
    STMFD   r1!, {r4 - r11}    ;向原线程栈入栈R4--R11,同时调整R1
    LDR     r0, [r0]           ;取原线程控制块栈指针*sp,即rt_interrupt_from_thread
    STR     r1, [r0]           ;sp更新为最新的栈指针,即完成入栈操作的R1
    ;【5】对目的线程进行环境恢复
switch_to_thread
    LDR     r1, =rt_interrupt_to_thread
    LDR     r1, [r1]
    LDR     r1, [r1]            ; R1用作目的线程栈指针
    LDMFD   r1!, {r4 - r11}     ; 从目的线程栈出栈 R4-R11,同时调整R1
    MSR     psp, r1             ; 线程模式堆栈指针psp更换为目的线程栈指针,即完成出栈操作的R1
    ;【6】完成手动部分,恢复屏蔽,进行自动出栈
pendsv_exit
    MSR     PRIMASK, r2         ; 恢复屏蔽寄存器
    ORR     lr, lr, #0x04       ; 出栈默认寄存器
    BX      lr                  ; 执行BX 0xFFFFFFFD,返回用户级线程模式,根据堆栈指针psp,
                                ; 自动出栈R0、R1、R2、R3、R12、R14(LR)、R15(PC)、XPSR
    ENDP

5.3.4 上下文切换逻辑图

5.4 上下文切换实例分析

        假设线程A由运行态切换到了阻塞态,而线程B是当前最高优先级的就绪态任务,线程A主动启动PendSv中断,上下文切换过程如下所示:

        由上图可见,对比切换前和切换后,线程A和线程B的栈状态正好相反,线程A进行了环境保存,线程B进行了环境恢复。

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

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

相关文章

OC IOS 文件解压缩预览

热很。。热很。。。。夏天的城市只有热浪没有情怀。。。 来吧,come on。。。 引用第三方库: pod SSZipArchive 开发实现: 一、控制器实现 头文件控制器定义: // // ZipRarViewController.h // // Created by carbonzhao on 2…

solidworks 3D草图案例2-方块异形切

单位mm 单位mm 长方体 底面是48mm*48mm,高为60mm 3D草图 点击线,根据三视图,绘制角度线, 由于三点确定一个面,因此确定三点就可以了 基准面 点击参考几何体-基准面,依次点击3个点 曲面切除 完成后点击插…

02--大数据Hadoop集群实战

前言: 前面整理了hadoop概念内容,写了一些概念和本地部署和伪分布式两种,比较偏向概念或实验,今天来整理一下在项目中实际使用的一些知识点。 1、基础概念 1.1、完全分布式 Hadoop是一个开源的分布式存储和计算框架&#xff0…

Serverless应用引擎SAE评测|一分钟部署在线游戏

Serverless应用引擎SAE评测|一分钟部署在线游戏 什么是Serverless应用引擎SAE一分钟部署在线游戏SAE控制台 资源释放其他操作 在进行Serverless应用引擎SAE评测之前,首先需要了解一下什么是SAE。 什么是Serverless应用引擎SAE Serverless应用引擎SAE(Se…

超频是什么意思?超频的好处和坏处

你是否曾经听说过超频?在电脑爱好者的圈子里,这个词似乎非常熟悉,但对很多普通用户来说,它可能还是一个神秘而陌生的存在。 电脑超频是什么意思 电脑超频(Overclocking),顾名思义,是…

C++面向对象程序设计 - 标准输出流

在C中,标准输出流通常指的是与标准输出设备(通常是终端或控制台)相关联的流对象。这个流对象在C标准库中被定义为std::cout、std::err、std::clog,它们是std::ostream类的一个实例。 一、cout,cerr和clog流 ostream类…

VLDB ’25 最后 6 天截稿,58 个顶会信息纵览;ISPRS 城市分割数据集上线

「顶会」板块上线 hyper.ai 官网啦!该板块为大家提供最新最全的 CCF A 类计算机顶会信息,包含会议简介、截稿倒计时、投稿链接等。 你是不是已经注册了顶会,但对截稿时间较为模糊,老是在临近 ddl 时才匆忙提交;又或者…

监控云安全的9个方法和措施

如今,很多企业致力于提高云计算安全指标的可见性,这是由于云计算的安全性与本地部署的安全性根本不同,并且随着企业将应用程序、服务和数据移动到新环境,需要不同的实践。检测云的云检测就显得极其重要。 如今,很多企业…

模拟量4~20mA电流传感器接线方式

一、模拟量4~20mA电流传感器接线方式 无源双线制是常见的电流型传感器接线方式,它具有简单、经济的特点。其接线方式如下: 传感器的“”接到数据采集器的电源“”上, 传感器的“-”端子连接到数据采集器的“AI”端子上, 数据采集器…

翻译《The Old New Thing》- What did MakeProcInstance do?

What did MakeProcInstance do? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20080207-00/?p23533 Raymond Chen 2008年02月07日 MakeProcInstance 做了什么? MakeProcInstance 宏实际上什么也不做。 #define MakeProcInst…

HackTheBox-Machines--Beep

Beep测试过程 1 信息收集 nmap端口扫描 gryphonwsdl ~ % nmap -sC -sV 10.129.137.179 Starting Nmap 7.94 ( https://nmap.org ) at 2024-05-28 14:39 CST Nmap scan report for 10.129.229.183 Host is up (0.28s latency). Not shown: 988 closed tcp ports (conn-refused…

python办公自动化——(二)替换PPT文档中图形数据-柱图

效果: 数据替换前 : 替换数据后: 实现代码 import collections.abc from pptx import Presentation from pptx.util import Cm,Pt import pyodbc import pandas as pd from pptx.chart.data import CategoryChartData…

C语言 数组—— 一维数组下标越界问题分析

目录 数组元素的访问 一维数组元素的越界访问 二维数组元素的越界访问 小结 数组元素的访问 访问数组元素时, 下标越界 是大忌!  编译器通常不检查下标越界,导致程序运行时错误  下标越界,将访问数组以外的空间  …

如何学到数据库从入门到入土(MySQL篇)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接…

开源AI模型:未来发展的领航者!

开源AI模型简单概述 开源AI模型是指那些其源代码可以自由使用、修改和分发的人工智能模型。这些模型通常由社区成员共同开发,并且可以在遵守相应许可证的前提下被任何人用于商业或研究目的。开源AI模型的出现极大地推动了人工智能技术的发展,使得更多的…

uniapp - 文章模块页面

在上一篇文章中,创建了一个空白的文章模块页面。在这一篇文章,让我们来向页面中填充内容。 目录 页面效果涉及uniapp组件1.view2.swiper3.scroll-view4.属性解读1) class"style1 style2 .."2) circular单属性无赋值3) :autoplay"autoplay…

gitlab将本地文件项目上传至gitlab服务

打开gitlab网页界面,登陆管理员账号 (测试服务器安装的gitlab,浏览器输入ip或配置的gitlab地址) 创建新项目 使用gitlab创建项目 创建一个新项目(忽略分组) (忽略分组) 在创建工…

网络原理-------TCP协议

文章目录 TCP协议TCP协议段格式TCP原理确认应答机制 (安全机制)超时重传机制 (安全机制)连接管理机制 (安全机制)滑动窗口 (效率机制)流量控制 (安全机制)拥塞控制 (安全机制)延迟应答 (效率机制)捎带应答 (效率机制) 基于TCP的应用层协议 TCP协议 TCP, 即 Transmission Contr…

鸿蒙OS开发:【一次开发,多端部署】(导航栏) 导航栏

一多导航栏 介绍 本示例展示了导航组件在不同设备形态下的样式。 在sm设备上,以tabs形式展示,内容、导航为上下样式布局,通过点击底部tabs切换内容;在md/lg设备上,以[SideBarContainer]形式展示,内容、导…

OZON平台支持什么ERP,芒果店长ERP

随着跨境电商行业的飞速发展,越来越多的电商平台与ERP系统展开了紧密的合作,旨在通过技术整合提升商家的运营效率和市场竞争力。在众多电商平台中,OZON以其独特的商业模式和强大的市场影响力,吸引了众多商家的目光。而芒果店长ERP…