uCOSIII实时操作系统 四 任务管理

news2024/11/17 3:32:20

目录

uCOSIII启动过程:

stm32的启动过程:

uCOSIII的启动过程:

任务状态:

任务控制块:

任务堆栈:

任务就绪表:

优先级位映射表//OSPrioTbl[]

位映射表:

查找优先级:

什么是前导零指令呢?

就绪任务列表OSRdyList[]

任务的调度与切换

调度基础:

任务调度器:

中断级调度器:

时间片轮转调度:


uCOSIII启动过程:

stm32的启动过程:

在系统上电的时候第一个执行的是启动文件(.s文件)里边由汇编语言编写的复位函数Reset_Handler.复位函数的最后会调用C库函数_main,_main()函数的主要工作是初始化系统的堆和栈,最后调用C中的main()函数,进入C的编译环境下。

uCOSIII的启动过程:

uCOSIII启动是有一定顺序的所以在使用的时候按照顺序打开

  1. 调用OSInit()初始化UCOSIII系统。
  2. 创建任务。一般来说只在main()函数中创建一个开始(start_task)任务,其他任务在该任务中进行创建。创建任务之前,使用OS_CRITICAL_ENTER()函数进入临界区域,再利用OSTaskCreate()函数创建任务,任务创建完之后利用OS_CRITICAL_EXIT()退出临界状态。(RT-Thread和FreeRTOS则默认使用这种形式)。
  3. 当任务创建好后,就是处于任务就绪。在就绪态的任务可以参加操作系统的调度,任务调度器只启动一次,之后就不会在执行了,uCO/OS中启动任务调度器的函数是OSStart(),并且启动任务调度器的时候就不回返回了,从此任务都是由uCOS管理。调用OSStart()函数开启UCOSIII系统。

流程图可表示为:

打开main函数,代码如下:

int main(void)
{

OS_ERR err;
CPU_SR_ALLOC();
/***********STM32硬件初始化***********/
delay_init(168); //时钟初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
uart_init(115200); //串口初始化
LED_Init(); //LED初始化
/***************END******************/

//第一步://初始化UCOSIII
OSInit(&err); 

//第二步://进入临界区
OS_CRITICAL_ENTER();

//第三步://创建开始任务
OSTaskCreate((OS_TCB * )&StartTaskTCB, //任务控制块
(CPU_CHAR * )"start task", //任务名字
(OS_TASK_PTR )start_task, //任务函数
(void * )0, //传递给任务函数的参数
(OS_PRIO )START_TASK_PRIO, //任务优先级
(CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址
(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位
(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小
(OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
(OS_TICK )0, //当使能时间片轮转时的时间片长度,为0时为默认长度,
(void * )0, //用户补充的存储区
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
(OS_ERR * )&err); //存放该函数错误时的返回值

//第四步:退出临界区
OS_CRITICAL_EXIT(); //退出临界区

//第五步:开启UCOSIII
OSStart(&err); //开启UCOSIII
while(1);
}

任务状态:

UCOSIII支持的是单核CPU,不支持多核CPU,这样某一时刻只有一个任务会获得CPU的使用权进入运行态,其他任务就会进入其他状态,

UCOSIII有多个任务态 参考该篇文章的任务状态 http://t.csdnimg.cn/5OTXd

任务控制块:

引入:在裸机系统中,程序的主体是 CPU 按照顺序执行的。而在多任务系统中,任务的执行是由系统调度的。

系统为了顺利的调度任务使用OSTaskCreate()函数来创建任务的时候,为每一个任务定义了一个控制块TCB(Task ConTrol Block),这个任务控制块就相当于任务的身份证,里边含有任务的所有信息,比如任务的堆栈,任务名称,任务的形参等。有了这个控制块之后,以后系统对任务的全部操作都可以通过这个TCB来实现。

任务堆栈:

暂停一个任务,以后又能恢复运行,必须考虑将这个运行的信息保存,而回复运行的时候需要将这些信息恢复到运行环境。所以任务切换必须做环境的保护和恢复操作。

因此每个任务都应该有自己的堆栈,下面创建一个堆栈:

1、定义一个CPU_STK变量,在UCOSIII中CPU_STK数据类型用来定义任务堆栈。

//任务堆栈大小
#define LED0_STK_SIZE 128
//任务控制块
OS_TCB Led0TaskTCB;
//任务堆栈
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];

2、在使用OSTaskCreat()函数创建任务的时候将堆栈地址转递给OSTaskCreate函数的参数p_stk_base,将堆数据深度传递给参数stk_limit,堆栈深度通常为堆栈大小的十分之一,主要用来检测堆栈是否为空,将堆栈大小转递给stk_size。

(CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址
(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位
(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小

任务就绪表:

引入:多任务操作系统的主要工作是为系统中处于就绪状态的任务分配CPU资源。

其中涉及到的两个关键:

  1. 判断那些任务处于就绪状态(找优先级)。
  2. 确定那个任务应该马上得到执行(找任务)。

在UCOSIII中,所有已经就绪等待的任务都会被放在一个所谓的就绪表当中,任务就绪表包括两部分:

  1. 一个优先级位映射表OSPrioTbl[],用来标注那个优先级下有任务就绪。
  2. 一个是就绪任务列表OSRdyList[],用来记录每一个优先级下所有的就绪任务,其中包括指向各个就绪任务的指针。

优先级位映射表//OSPrioTbl[]

OSPrioTbl[]在os_prio.c中有定义:
CPU_DATA OSPrioTbl[OS_PRIO_TBL_SIZE]; //UCOSIII_CORE中os_prio.c中41行

根据CPU_DATA的值,该表的成员元素的宽度可以为8,16,32位,跳转可知:

在STM32中CPU_DATA为unsigned int,有4个字节,32位。因此表OSPrioTbl每个参数有32位。其中每个位对应一个优先级,当某个任务就绪之后就会将优先级映射表中相应的位置1。

UCOSIII 中任务数目由宏 OS_CFG_PRIO_MAX 配置的(见 os_cfg.h)。

UCOS-III和逻辑一样,数值越小,优先级越高,因此优先级0是优先级最高的。 优先级OS_CFG_PRIO_MAX-1 的优先级最低(也就是63)。uCOSIII将最小优先级唯一的分配给空闲任务,其他任务不允许被设置为这个优先级。当任务准备好运行了,根据任务的优先级,位映像表中相应位就会被设置为 1。(如果处理器支持位清零指令 CLZ,这个指令会加快位映像表的设置过程。)

位映射表:

根据映射表可以知道OSPrioTb[]的大小是32位(unsigned int)在UCOSIII中咱们得中断有64个优先级,所以两个OSPrioTb[]既可以撑起咱们64个优先级。

想要验证OSPrioTb[]的个数是否为2通过OS_PRIO_TBL_SIZE转跳进入在os.h中

查找优先级:

UCOSIII中优先级是怎么查找的?

  1. 遍历OSPrioTb[]
  2. 判断OSPrioTb[N]是否等于0
  3. 若不为0找出不为零的那位(从左往右)

在UCOSIII中定义了函数OS_PrioGetHighest()用于找到就绪了的最高优先级的任务(位置:os_prio.c中85行 )

//源码分析
OS_PRIO  OS_PrioGetHighest (void)
{
    CPU_DATA  *p_tbl;
    OS_PRIO    prio;


    prio  = (OS_PRIO)0;

    //从OSPrioTbl[0]开始扫描映射表,一直遇到非零项。
    p_tbl = &OSPrioTbl[0];

    while (*p_tbl == (CPU_DATA)0) {   

        //当数组OSPrioTbl[]中的某个元素为零的时候,就继续扫描下一个数组的元素, prio 加  DEF_INT_CPU_NBR_BITS(32)                   
        prio += DEF_INT_CPU_NBR_BITS;   
        
        //p_tbl加一,继续寻找OSProTb[]中的下一个元素                    
        p_tbl++;
    }
    

    //一旦找到一个非0项,再加上该项的前导0的数量(从左到右第一为1的位置),就找到了最高优先级任务了。
    prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl);             
    return (prio);
}

注意:一个操作系统如果只是具备了高优先级任务能够“立即”获得处理器并得到执行的特点,那么它仍然不算是实时操作系统。因为这个查找最高优先级任务的过程决定了调度时间是否具有实时性。

例如一个包含 n 个就绪任务的系统中,如果仅仅从头找到尾,那么这个时间将直接和 n 相关,而下一个就绪任务抉择时间的长短将会极大的影响系统的实时性。

μC/OS 内核中采用两种方法寻找最高优先级的任务,第一种是通用的方法,因为 μC/OS 防止 CPU平台不支持前导零指令,就采用 C 语言模仿前导零指令的效果实现了快速查找到最高优先级任务的方法。而第二种方法则是特殊方法,利用硬件计算前导零指令 CLZ,这样子一次就能知道哪一个优先级任务能够运行,这种调度算法比普通方法更快捷,但受限于平台(在 STM32 中我们
就使用这种方法)。

什么是前导零指令呢?

如果分别建立了优先级3,5,8,11这个四个任务,任务创建成功之后,调用CPU_CntLeadZeros()我们可以计算出 OSPrioTbl[0] 第一个置 1 的位前面有 3 个 0,那么这个 3 就是我们要查找的最高优先级,至于后面还有多少个位置 1 我们都不用管,只需要找到第一个 1 即可。

就绪任务列表OSRdyList[]

通过上一步我们已经知道了哪一个优先级的任务已经就绪,但是UCOSIII支持时间片轮转调度,同一个优先级下可以有多个任务。而就绪任务列表OSRdyList[]就是用来记录优先级每个优先级所有的就绪任务。

准备运行好的任务放到就绪列表当中。就绪列表是一个数组OSRdyList[],它一共有 OS_CFG_PRIO_MAX 条记录,记录的数据类型为 OS_RDY_LIST( 见 OS.H)。如下图所示

转跳进该数据类型之后就绪列表中的每条记录都包含了三个变量NbrEntries,TailPtr,HeadPtr

NbrEntries:表示的是该优先级就绪任务数。当优先级没有就绪任务的时候,该变量的值被设置为0;

.TailPtr 和.HeadPtr 用亍该优先级就绪任务的建立双向列表。.HeadPtr 指向列表的头部,TailPtr 指向列表的尾部。

下图当有两个任务的时候逻辑图如下,此时NbrEntries=2

任务的调度与切换

调度基础:

调度器,决定了任务的运行顺序,UCOSIII是一个可以抢占优先级的,基于优先级内核。根据起重要性每个任务分配一个优先级。UCOSIII支持多个任务拥有相同的优先级(这一点UCOSII中没有)。

操作系统通过两个函数完成任务的调度功能:

  1. OSSched():在任务级被调用
  2. OSIntExit():在中断级被调用

确定哪个任务优先级最高,下面该哪个任务运行了的工作是由调度器(Scheduler)完成的

任务调度器:

源码的位置:os_core.c:

源码分析:

//OSSched为任务级调度器,在中断服务函数中不能使用
void  OSSched (void)
{
    CPU_SR_ALLOC();


    如果在中断服务子程序中调用OSSched(),此时中断嵌套层数>0。函数return直接返回
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) 
    {              
        return;                                             
    }

    //用户至少调用了一次给任务调度上锁函数OSSchedLock(),使OSSchedLockNestingCtr>0。函数return直接返回
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0)
    {        
        return;                                             
    }

    在任务执行的时候不希望中断打断任务执行,所以先关闭中断
    CPU_INT_DIS();

    //从后边的注释可以知道是获取准备好的最高优先级,(从任务就绪表中获取)
    OSPrioHighRdy   = OS_PrioGetHighest();                  /* Find the highest priority ready                        */

    //获取下次任务切换要运行的任务,OSTCBHighRdyPtr指向将要切换任务的OS_TCB(任务块)
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;

    //判断要运行的任务是否是正在运行的任务,是就不用切换
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                   /* Current task is still highest priority task?           */
        CPU_INT_EN();                                       /* Yes ... no need to context switch                      */
        return;
    }

#if OS_CFG_TASK_PROFILE_EN > 0u
    OSTCBHighRdyPtr->CtxSwCtr++;                            /* Inc. # of context switches to this task                */
#endif
    OSTaskCtxSwCtr++;                                       /* Increment context switch counter                       */

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_TaskSw();
#endif

    //调用OS_TASK_SW()来完成实际上的任务切换
    OS_TASK_SW();                                           /* Perform a task level context switch                    */
    //开启中断
    CPU_INT_EN();
}

有时候我们并不希望发生任务调度,因为始终有一些代码的执行过程是不能被打断的。此时我们就可以使用函数OSSchedLock()对调度器加锁,当我们想要恢复任务调度的时候就可以使用函数OSSchedUnlock()给已经上锁的任务调度器解锁。

注意:OSSched()中真正执行任务切换的宏OS_TASK_SW()(在os_cpu.h中定义),宏OS_TASK_SW()就是函数OSCtxSW(),OSCtxSW()是os_cpu_a.asm中汇编编写的一段代码,OSCtxSW()要做的就是将当前任务的CPU寄存器的值保存在堆栈当中,也就是现场保护,保存完当前任务的的现场后将新的任务OS_TCB中保存任务堆栈指针加载到CPU的堆栈指针寄存器中,最后还要从新任务的堆栈重恢复CPU寄存器的值。

中断级调度器:

OSIntExit();位置:os_core.c中第300行

//中断级任务调度器
void  OSIntExit (void)
{
    CPU_SR_ALLOC();//进入临界段


    //判断UCOSIII是否执行
    if (OSRunning != OS_STATE_OS_RUNNING) {                 /* Has the OS started?                                    */
        return;                                             /* No                                                     */
    }

    //关闭中断防止被中断打断的代码
    CPU_INT_DIS();

    OSIntNestingCtr中断嵌套计数器,判断是否为0
    if (OSIntNestingCtr == (OS_NESTING_CTR)0) {             /* Prevent OSIntNestingCtr from wrapping                  */
        CPU_INT_EN();
        return;
    }

    //中断层数减一
    OSIntNestingCtr--;//因为OSIntExit()是在退出中断服务函数时调用的,因此中断嵌套计数器要减1

    ///若 OSIntNestingCtr大于0时,说明还有其他的中断发生,那么跳回到中断服务程序中不需要任务切换
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* ISRs still nested?                                     */
        CPU_INT_EN();                                       /* Yes                                                    */
        return;
    }

    //检查调度器是否加锁,如果加锁的话就直接跳出,不需要做任何任务切换
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {        /* Scheduler still locked?                                */
        CPU_INT_EN();                                       /* Yes                                                    */
        return;
    }

    //接下来的五行程序和任务级调度器是一样的,从OSRdyList[]中取出最高优先级的任务控制块OS_TCB
    OSPrioHighRdy   = OS_PrioGetHighest();                  /* Find highest priority                                  */
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;     /* Get highest priority task ready-to-run                 */
    if (OSTCBHighRdyPtr == OSTCBCurPtr) {                   /* Current task still the highest priority?               */
        CPU_INT_EN();                                       /* Yes                                                    */
        return;
    }

#if OS_CFG_TASK_PROFILE_EN > 0u
    OSTCBHighRdyPtr->CtxSwCtr++;                            /* Inc. # of context switches for this new task           */
#endif
    OSTaskCtxSwCtr++;                                       /* Keep track of the total number of ctx switches         */

#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS_TaskSw();
#endif

    //调用中断级任务切换函数
    OSIntCtxSw();  
                                         /* Perform interrupt level ctx switch                     */
    //开启中断
    CPU_INT_EN();
}

注意:

在中断级调度器中真正完成任务切换的就是中断级任务切换函数OSIntCtxSWO(),与任务级切换函数 OSCtxSWO()不同的是,由于进入中断的时候现场已经保存过了,所以 OSIntCtxSWO()不需要像OSCtxSWO()一样先保存当前任务现场,只需要做 OSCtxSWO()的后半部分工作,也就是从将要执行的任务堆栈中恢复 CPU 寄存器的值。

时间片轮转调度:

UCOSIII 是支持多个任务拥有同一个优先级的,当多个任务有相同的优先级的时候,这些任务采用时间片轮转调度方法进行任务调度,uC/OS-III 允许每个任务运行规定的时间片,当任务没有用完分配给他的时间片它可以自愿地放弃 CPU。uC/OS-III 允许任务在运行时开启戒者关闭循环轮转调度。在 os_cfg.h 文件中有个宏 OS_CFG_SCHED_ROUND_ROBIN_EN,我们要想使用时间片轮转调度就需要将OS_CFG_SCHED_ROUND_ROBIN_EN 定义为 1这样 UCOSIII中有关时间片轮转调度的代码才会被编译,否则不能使用时间片轮转调度。

下边是正点原子对时间片轮转调度的解释:

UCOSIII通调用OS_SchedRoundRobin()函数来完成就会切换到该优先级对应的下一任务中。

该函数的位置:

源码解释:

//源码解析
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
void  OS_SchedRoundRobin (OS_RDY_LIST  *p_rdy_list)
{
    OS_TCB   *p_tcb;//任务控制块变量
    CPU_SR_ALLOC();//进入临界段


    //检查是否开启了时间片轮转调度
    if (OSSchedRoundRobinEn != DEF_TRUE) {                  /* Make sure round-robin has been enabled                 */
        return;
    }


    CPU_CRITICAL_ENTER();//关闭中断

    //获得最高优先级的就绪任务(指针地址)
    p_tcb = p_rdy_list->HeadPtr;                            /* Decrement time quanta counter                          */

    //无任务
    if (p_tcb == (OS_TCB *)0) {
        CPU_CRITICAL_EXIT();
        return;
    }

    //判断是否为空闲任务
    if (p_tcb == &OSIdleTaskTCB) {
        CPU_CRITICAL_EXIT();
        return;
    }

    //判断当前任务的时间片是否还有
    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {
        p_tcb->TimeQuantaCtr--;
    }

    //是否还剩余时间片,有的话就跳出去返回
    if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {                /* Task not done with its time quanta                     */
        CPU_CRITICAL_EXIT();
        return;
    }

    //NbrEntries是代表的某个优先级下的任务,这里判断是否小于2,小于2就不用进行任务切换了直接返回
    if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {           /* See if it's time to time slice current task            */
        CPU_CRITICAL_EXIT();                                /* ... only if multiple tasks at same priority            */
        return;
    }

    //判断调度器是否上锁上锁的话直接返回
    if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {        /* Can't round-robin if the scheduler is locked           */
        CPU_CRITICAL_EXIT();
        return;
    }

    //当执行到这一步的时候说明当前任务的时间片已经用完了,将当前任务的任务块OS_TCB从双向链表的链表头移到链表尾()
    OS_RdyListMoveHeadToTail(p_rdy_list);                   /* Move current OS_TCB to the end of the list             */
//从这开始都是在为下一次任务做铺垫
    //重新获取新的双向链表表头也就是下一个要执行的任务
    p_tcb = p_rdy_list->HeadPtr;                            /* Point to new OS_TCB at head of the list                */

    //是否使用默认时间片长度第一个默认,第二个用户指定的值
    if (p_tcb->TimeQuanta == (OS_TICK)0) {                  /* See if we need to use the default time slice           */
        p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
    } else {
        p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta;           /* Load time slice counter with new time                  */
    }

    CPU_CRITICAL_EXIT();//开启中断
}
#endif

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

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

相关文章

GNN+RA 文献阅读

[1] X. Wang et al., ‘Scalable Resource Management for Dynamic MEC: An Unsupervised Link-Output Graph Neural Network Approach’. paper code&#xff1a;GitHub - UNIC-Lab/LOGNN: This is the code for paper "Scalable Resource Management for Dynamic MEC:…

Linux[find命令]-根据路径和条件搜索指定文件并删除

一、find命令简介 find命令&#xff1a;用于根据给定的路径和条件查找相关文件或目录&#xff0c;参数灵活方便&#xff0c;且支持正则表达式&#xff0c;结合管道符后能够实现更加复杂的功能。 基本语法格式&#xff1a;find pathname -options 搜索内容 [其他选项] pathname…

链表(2)——带头双向循环链表

&#x1f341;一、链表的分类 &#x1f315;1.单向或者双向 &#x1f315;2.带头或者不带头&#xff08;有无哨兵&#xff09; &#x1f315;3.循环或者不循环 &#x1f315;4.无头单向非循环链表&#xff08;常用&#xff09; &#x1f315;5.带头双向循环链表&#xff08;常用…

SNMP报文与MIB Browser软件讲解

目录 SNMP报文结构 MIB Browser软件讲解 具体的操作步骤 MIB操作方式 SNMP报文结构 UDP端口读/写为161&#xff0c;Trap为162 版本号 版本号 名称 0 V1 1 V2c 2 V3 团体字 团体字相当于管理方和被管理方进行校验的密钥 读写团体字 两端需要配置为一致 PDU类型——标…

5项先进采购技术,帮助你的企业脱颖而出

持续的改进对保持每个企业的正常运转有着重要作用&#xff0c;采购部门也不例外。 以前&#xff0c;采购团队主要关注两个方面&#xff1a;降低成本和减少风险。随着自动化和云服务的兴起&#xff0c;如今他们还需要关注采购决策的效率、可访问性和可持续性。 技术与采购的融合…

python中pytorch的广播机制——Broadcasting

广播机制 numpy 在算术运算期间采用“广播”来处理具有不同形状的 array &#xff0c;即将较小的阵列在较大的阵列上“广播”&#xff0c;以便它们具有兼容的形状。Broadcasting是一种没有copy数据的expand 不过两个维度不相同&#xff0c;在前面插入维度1扩张维度1到相同的维…

轻盈百搭头戴式耳机——umelody轻律 U1头戴式复古耳机分享

最近买了款热门的轻律U1头戴式耳机&#xff0c;今天和大家来分享一下&#xff0c;看看究竟效果怎样呢&#xff1f; UMELODY轻律品牌将复古潮流文化结合与音频设备之中&#xff0c;一直以来致力于音频领域的研究和创新。产品外观定位时下流行之‘Retro Futurism’ “ 复古未来主…

软件测试工程师岗位核心任务

最近转正&#xff0c;需要完成一个OA任务&#xff0c;其中有一项“你认为软件测试工程师岗位核心任务是什么&#xff1f;”要求写出三到五条&#xff0c;并简单地阐明。 这个问题似乎很好回答&#xff0c;软件测试工程师不就是做测试&#xff1f;仅仅这样吗&#xff1f;小酋抠…

进程相关介绍(一)

目录 进程标识符 查看进程的标识符 ps axj | head -1&& ps axj | grep 程序名 ls /proc/进程标识符 获得进程标识符 getpid()函数 getppid()函数 创建一个子进程 fork函数解析 fork函数返回子进程的pid给父进程的原因 fork函数有两个返回值的原因 一个进程实质上就是一…

【每日一记】OSPF中Hello报文详讲

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;喜欢编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc…

SpringBoot 实现EMQ设备的上下线告警

前言 上下线通知 我遇到了一个难题&#xff0c;即在使用EMQ X 4.4.10的开源版本时&#xff0c;我需要实现设备的上下线状态监控&#xff0c;但该4.4.10开源版本并未内置设备上下线提醒模块&#xff0c;只有企业版才内置了该模块。这为我带来了一些技术上的难题&#xff0c;迫…

远程办公软件的未来趋势:预测2023年及以后的发展方向

随着科技的迅速发展&#xff0c;远程办公已经成为现代工作方式的重要组成部分。远程办公软件在过去几年中取得了巨大的进步&#xff0c;并且在全球范围内被广泛使用。本文将探讨远程办公软件在2023年及以后可能的发展方向&#xff0c;包括增强的协作功能、智能化的辅助工具、改…

坦克 400 Hi4-T:用产品诠释越野新能源

9 月 25 日&#xff0c;坦克 400 Hi4-T 正式上市&#xff0c;新车共推出两款车型配置&#xff0c;售价区间 27.98-28.98 万元。同时&#xff0c;坦克 400 Hi4-T 将上市及即交付。 权益方面&#xff0c;坦克 400 Hi4-T 共有七重好礼&#xff1a; 质保无忧&#xff1a;整车 5 年…

02 认识Verilog HDL

02 认识Verilog HDL ‍ 对于Verilog的语言的学习&#xff0c;我认为没必要一开始就从头到尾认真的学习这个语言&#xff0c;把这个语言所有细节都搞清楚也不现实&#xff0c;我们能够看懂当前FPGA的代码的程度就可以了&#xff0c;随着学习FPGA深度的增加&#xff0c;再不断的…

Autosar诊断实战系列24-0x2E服务代码级分析及ECU-Pending期间的处理

本文框架 前言1. UDS-0x2E服务逻辑整理2. Pending期间ECU的处理3. 相关工程问题思考前言 开始本篇讲述前,先抛出几个问题,UDS 2E服务在执行过程中进行了哪些操作?在2E写期间由于要操作NvM,会执行时间较长导致ECU先回复NRC 0x78,这期间ECU在进行哪些处理?ECU是如何判断2E…

单目标应用:蚁群算法(Ant Colony Optimization,ACO)求解微电网优化MATLAB

一、微网系统运行优化模型 微电网优化模型介绍&#xff1a; 微电网多目标优化调度模型简介_IT猿手的博客-CSDN博客 二、蚁群算法ACO 蚁群算法&#xff08;Ant Clony Optimization&#xff0c; ACO&#xff09;由意大利学者Colorni A., Dorigo M. 等于1991年提出&#xff0c…

开啥玩笑?一个SSD硬盘可以使用100多年?MTBF正解

在之前文章中&#xff0c;有一个参数“平均无故障时间”&#xff0c;对应的参数是MTBF&#xff0c;比如这个盘MTBF150万小时。 小编发现有一些朋友对这个参数还有误解。大家看到这个参数误认为盘可以使用150万小时都没有发生故障。如果真的是这样&#xff0c;那么这盘的质量简直…

基于springboot实现家具销售电商平台管理系统项目【项目源码+论文说明】

基于springboot实现家具销售电商平台管理系统演示 摘要 社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。网络计算机的交易方式逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个用户的使用。互联网具有便利性&#xff0c;速度快&#xff0c;效率高&am…

【OSPF宣告——network命令与多区域配置实验案例】

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;喜欢编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc…

ChatGLM2-6B微调实践-P-Tuning方案

ChatGLM2-6B微调实践 环境准备安装部署1、安装 Anaconda2、安装CUDA3、安装PyTorch4、安装 ChatGLM2-6B 微调实践1、准备数据集2、安装python依赖3、微调并训练新模型4、微调后模型的推理与评估5、验证与评估微调后的模型6、微调模型优化7、P-Tuning微调灾难性遗忘问题 微调过程…