3-FreeRTOS任务和协程

news2024/11/25 22:53:02

概述

“任务”的特征

简单来说,FreeRTOS实时系统能够创建多个独立的任务,任务之间互不干扰。任务创建之后并不是一起运行的,而是通过优先级顺序进行任务的调用,和调度也没有依赖关系。所以不管什么时候程序只能执行一个任务,只有当该任务执行完成或者被打断才能执行下一个任务。具体应该执行那个任务是由调度器来进行负责,因此RTOS可以重复的启动和停止每个任务。这里RTOS调度器为了确保处理器在进行任务交换时的环境(寄存器、堆栈内容)与交换之后的任务是完全相同。
因此,为了这一点的实现,每个任务都应该有自己的堆栈空间。当任务进行切换,执行环境则保存到该任务的堆栈中,所以,当一段时间后切换回该任务,它能够精确地回复上次工作时的状态。

任务总结

  1. 简单
  2. 没有使用限制
  3. 支持全部的抢占优先级
  4. 完全优先
  5. X每个任务都有自己的堆栈,会导致RAM的使用空间增加
  6. 若是使用优先级,应该考虑优先级的问题

协程特征

在使用协程时,应该注意协程时为了非常小的设备实现的,现在已经很少在实际中应用。
虽然这些代码并没有删除,但是官方目前也没有进一步开发的打算。因此,如果你使用了,应该注意一些。
协程其实和任务差不多,但是还是有一些区别的:
比如以下这几点:
1.堆栈
协程是没有堆栈分配的,是所有创建的协程共同使用一个堆栈空间,这相比于任务来说,减少了RAM的使用空间。
2. 调度和优先级
协程使用协同调度,但是可以包含在使用的抢占优先级之中。
3. 宏定义
协程例程实现是通过一组宏提供的。
4. 条件限制
RAM使用量的减少是以在如何构建协程方面的一些严格限制为代价的。

协程总结

在协程之间共享堆栈会大大降低RAM使用量。

协程操作使再入问题变得不那么严重。

跨架构的可移植性很强。

完全优先级相对于其他协程,但如果两者混合,总是可以被任务抢占。

缺乏堆栈需要特别考虑。

API调用的位置限制。

协程操作只在协程之间进行。

1-任务

1.1 任务状态

任务可以是以下几种状态中的一种:

1.1.1 运行

当任务实际执行时,它被称为处于正在运行状态。它当前正在使用处理器。 如果运行RTOS的处理器只有一个内核,那么 在任何给定时间只能是一个处于“正在运行”状态的任务。

1.1.2 就绪(准备)

就绪任务是那些能够执行的任务(它们没有处于阻塞或挂起状态),但目前没有执行,因为一个相同或更高优先级的不同任务已经处于运行状态。

1.1.3 阻塞

如果一个任务正在等待一个临时事件或外部事件,则该任务被称为处于阻塞状态。例如,如果一个任务调用vTaskDelay(),它将阻塞(被置于阻塞状态),直到延迟时间结束(一个临时事件)。任务也可以阻塞来等待队列、信号量、事件组、通知或信号量事件。处于阻塞状态的任务通常有一个“超时”时间,过了这个时间任务就会超时并被取消阻塞,即使任务等待的事件还没有发生。
处于“阻塞”状态的任务不占用任何处理时间,并且不能被选泽进入“运行中”的状态。

1.1.4 挂起

与“阻塞”状态的任务一样,处于“挂起”状态的任务不能被选择进入“正在运行”状态,但“挂起”状态的任务没有超时时间。相反,只有分别通过vTaskSuspend()和xTaskResume() 的API调用显式地命令任务进入或退出Suspended状态时,任务才会进入或退出Suspended状态。
图1是任务状态转换图:
图1-任务状态转换

2- 任务优先级

每个任务分配一个从0到(configMAX_PRIORITIES - 1)的优先级,其中configMAX_PRIORITIES是在FreeRTOSConfig.h中定义的(后面的章节会说一下这个头文件)。
如果正在使用的端口实现了端口优化的任务选择机制,该机制使用’计数前导零’类型的指令(用于单个指令中的任务选择),并且configUSE_PORT_OPTIMISED_TASK_SELECTION在FreeRTOSConfig.h中设置为1,那么configMAX_PRIORITIES不能超过32。在其他情况下,configMAX_PRIORITIES可以在合理范围内取任何值(由于用到RAM空间,因此在使用时,尽可能的保持实际需要的空间大小需求)。
FreeRTOS优先级设置是数字越大优先级越高。空任务的优先级是0(tskIDLE_PRIORITY)(注意:不同的系统优先级不同,有的OS是数字越小优先级越高,这点要注意一下)。
FreeRTOS调度器确保处于就绪或运行状态的任务总是优先于同样处于就绪状态的低优先级任务,优先获得处理器(CPU)时间。换句话说,处于运行状态的任务始终是运行优先级最高的任务。
不管多少个任务都可以共享相同的优先级。如果没有定义configUSE_TIME_SLICING,或者configUSE_TIME_SLICING设置为1,那么具有相同优先级的就绪状态任务将使用时间切片轮询调度方式共享可用的处理时间。

3-任务调度

3.1 RTOS调度(单核)

在默认情况下,FreeRTOS使用的是固定优先级抢占方式,对相同优先级的任务进行时间切换轮询方式。

  • “固定优先级”意味着调度器不会永久更改任务的优先级,尽管它可能由于优先级继承而临时提高任务的优先级。
  • “抢占式”意味着调度程序总是运行最高优先级RTOS任务,不管这个任务是什么时间可以运行。例如,如果中断服务例程(ISR)更改了能够运行的最高优先级任务,调度器将停止当前运行的低优先级任务并启动高优先级任务——即使这发生在一个时间片内。在这种情况下,低优先级任务被高优先级任务“抢占”了。
  • “循环”是指具有相同优先级的任务轮流进入运行状态。
  • 时间切片”意味着调度程序将在每个tick中断上在同等优先级的任务之间切换——tick中断之间的时间是一个时间切片(tick中断是RTOS用来测量时间的周期性中断)。

在使用抢占优先级调度程序时,应当避免任务互斥。
始终运行最高优先级任务的后果是,永远不会进入阻塞或挂起状态的高优先级任务将永久阻断所有低优先级任务的任何执行时间。这就是为什么最好创建事件驱动的任务的原因之一。例如,如果一个高优先级的任务正在等待一个事件,那么它就不应该处于该事件的循环(轮询)中,因为通过轮询,它始终在运行,因此永远不会处于阻塞或挂起状态。相反,任务应该进入阻塞状态来等待事件。可以使用众多FreeRTOS任务间通信和同步之一将事件发送给任务。接收到事件后,优先级更高的任务会自动从阻塞状态中移除。当高优先级任务处于阻塞状态时,低优先级任务将运行。

3.1.1配置RTOS调度策略

配置RTOS调度一般是在FreeRTOSConfig.h,当然你也可以在其他文件设置,但是这里不建议这么操作。
下面这些是更改默认时间调度的配置:

  1. configUSE_PREEMPTION
    如果configUSE_PREEMPTION为0,则抢占关闭,只有在运行状态任务进入阻塞或挂起状态、运行状态任务调用或中断服务例程(ISR)手动请求切换才会发生任务切换。
  2. configUSE_TIME_SLICING
    若configUSE_TIME_SLICING为0,则关闭时间切片,因此调度器不会在每个tick中断中在同等优先级的任务之间切换。

3.2 FreeRTOS AMP调度策略

使用FreeRTOS的非对称多处理(AMP)是指多核设备的每个内核运行自己独立的FreeRTOS实例。这些内核并不都需要具有相同的体系结构,但如果FreeRTOS实例需要彼此通信,则需要共享一些内存。
每个内核都运行自己的FreeRTOS实例,因此在任何给定的内核上的调度算法与上面描述的单核系统完全相同。可以使用流或消息缓冲区作为核间通信原语,以便一个核上的任务可以进入Blocked状态,以等待来自另一个核的数据或事件发送。

3.3 FreeRTOS SMP调度策略

使用FreeRTOS的对称多处理(SMP)是指FreeRTOS的一个实例跨多个处理器内核调度RTOS任务。由于FreeRTOS只有一个实例在运行,所以一次只能使用FreeRTOS的一个端口**,因此每个内核必须具有相同的处理器架构并共享相同的内存空间。**
FreeRTOS SMP调度策略使用与单核调度策略相同的算法,但与单核和AMP场景不同的是,SMP在任何给定时间会导致多个任务处于Running状态(每个内核有一个Running状态任务)。这意味着,只有在没有高优先级任务可以运行时,才会运行低优先级任务的假设不再成立。要理解其中的原因,就要考虑最初有一个高优先级任务和两个中等优先级任务都处于Ready状态时,SMP调度器将如何选择在双核微控制器上运行的任务。调度器需要选择两个任务,每个内核对应一个任务。首先,高优先级任务是能够运行的最高优先级任务,因此它将被选中用于第一个内核。这样就剩下两个中等优先级的任务作为能够运行的最高优先级的任务,因此会为第二个内核选择一个。结果是高优先级和中等优先级的任务同时运行。

3.3.1 配置SMP RTOS调度策略

下面的配置项有助于将为单核或AMP RTOS配置编写的代码移动到SMP RTOS配置,当这些代码依赖于这样一个假设:如果有一个高优先级的任务能够运行,那么低优先级的任务将不会运行。

configRUN_MULTIPLE_PRIORITIES

在FreeRTOSConfig.h文件中,如果configRUN_MULTIPLE_PRIORITIES设置为0,那么调度器将支持同时运行具有相同优先级的多个任务。这可能会修复假定一次只运行一个任务的代码,但代价是失去SMP配置的一些好处。
configUSE_CORE_AFFINITY
在FreeRTOSConfig.h文件中configUSE_CORE_AFFINITY被设置为1,那么可以使用vTaskCoreAffinitySet() API函数来定义一个哪些内核任务可以运行,哪些内核任务不运行,使用这种方法,可以防止两个任务同时执行,让他们对各自的执行顺序进行判断。

4-任务实现

4.1 任务执行

一个任务应该有以下结构:

    void vATaskFunction( void *pvParameters )
    {
        for( ;; )
        {
            -- Task application code here. --
        }

        /* Tasks must not attempt to return from their implementing
        function or otherwise exit.  In newer FreeRTOS port
        attempting to do so will result in an configASSERT() being
        called if it is defined.  If it is necessary for a task to
        exit then have the task call vTaskDelete( NULL ) to ensure
        its exit is clean. */
        vTaskDelete( NULL );
    }

TaskFunction_t类型被定义为一个返回void并将void指针作为唯一形参的函数。实现一个任务的所有函数都应该是这种类型。可以使用该参数将任何类型的信息传递到任务中—这可以通过几个标准的演示应用程序任务进行演示。(具体演示代码请查看文件夹下的演示例程)
如下演示代码:

/* main_full() is called from main() if the #define in main.c is set to create
the comprehensive demo, rather than simple blinky demo. */
int main_full( void )
{
   /* Setup the microcontroller hardware for the demo. */
   prvSetupHardware();

   /* Create the common demo application tasks, for example: */
   vStartInterruptQueueTasks();
   vStartMessageBufferAMPTasks()
   vCreatePollQTasks();
   Etc.

   /* Create any tasks defined within main.c itself, or otherwise specific to the
   demo being built. */
   xTaskCreate( vCheckTask, "check", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
   Etc.

   /* Start the RTOS scheduler, this function should not return as it causes the
   execution context to change from main() to one of the created tasks. */
   vTaskStartScheduler();

   /* Should never get here! */
   return 0;
}

任务函数不应该返回,因此通常作为连续循环实现。通常最好创建事件驱动的任务,这样就不会占用低优先级任务的处理时间,如下结构:

void vATaskFunction( void *pvParameters )
    {
        for( ;; )
        {
            /* Psudeo code showing a task waiting for an event 
            with a block time. If the event occurs, process it.  
            If the timeout expires before the event occurs, then 
            the system may be in an error state, so handle the
            error.  Here the pseudo code "WaitForEvent()" could 
            replaced with xQueueReceive(), ulTaskNotifyTake(), 
            xEventGroupWaitBits(), or any of the other FreeRTOS 
            communication and synchronisation primitives. */
            if( WaitForEvent( EventObject, TimeOut ) == pdPASS )
            {
                -- Handle event here. --
            }
            else
            {
                -- Clear errors, or take actions here. --
            }
        }

        /* As per the first code listing above. */
        vTaskDelete( NULL );
    }

具体的请查看例程代码尝试下面的这几个函数:
通过调用xTaskCreate()或xTaskCreateStatic()创建任务,通过调用vTaskDelete()删除任务。

4.2 任务宏的创建

任务函数可以使用portTASK_FUNCTION和portTASK_FUNCTION_PROTO宏来定义。提供这些宏是为了允许编译器把特定的语法分别添加到函数定义和原型中。它们的使用不是必需的,除非你使用的端口的文档中特别说明。
上面的原型可以写成下面这样:

void vATaskFunction( void *pvParameters );
Or,
portTASK_FUNCTION_PROTO( vATaskFunction, pvParameters );
Likewise the function above could equally be written as:
    portTASK_FUNCTION( vATaskFunction, pvParameters )
    {
        for( ;; )
        {
            -- Task application code here. --
        }
    }
 

当然具体的任务宏定义是需要根据你实现的功能函数进行任务宏定义的。

2-协程

2.1-协同状态

协程仅适用于对RAM有限制的处理器,一般情况下32位MCU是不会使用的(在这里还是给大家说一下,基础理论知识就全点)。

2.1.1 运行

当协程实际执行时,我们称其处于运行状态。当前处理器正在工作。

2.1.2 就绪

就绪的协程是那些能够执行(它们没有被阻塞)但目前没有执行的。协程可能处于Ready状态,一是 另一个具有同等或更高优先级的协程已经处于Running状态;二是任务处于Running状态(只有当应用程序同时使用任务和协程时,才会出现这种情况)。

2.1.3 阻塞

如果一个协程当前正在等待一个临时或外部事件,那么它就被称为处于Blocked状态。例如,如果一个协程调用crDELAY(),它将阻塞(被置于阻塞状态),直到延迟周期超时,一个临时事件。阻塞的协程无法用于调度。
下面是协程的通信图:

2.2 协程的实现

协程的结构如下:

   void vACoRoutineFunction( CoRoutineHandle_t xHandle,
                              UBaseType_t uxIndex )
    {
        crSTART( xHandle );

        for( ;; )
        {
            -- Co-routine application code here. --
        }

        crEND();
    }

类型crCOROUTINE_CODE被定义为一个返回void并将CoRoutineHandle_t和索引作为参数的函数。实现协程的所有函数都应该是这种类型的(上面的这段代码)。
协程的创建是通过xCoRoutineCreate()来进行的。
注意:

  • 所有协程函数都必须以调用crSTART()开始。
  • 所有协程函数都必须以对crEND()的调用结束。
  • 协程函数不应该返回,因此通常作为连续循环实现。
  • 可以从单个协程函数创建许多协程。
  • 提供 uxIndex 参数是为了区分此类 协程。

2.3-协程优先级

协程的优先级从0到(configMAX_CO_ROUTINE_PRIORITIES - 1)。configMAX_CO_ROUTINE_PRIORITIES在FreeRTOSConfig.h中定义,可以在应用程序的基础上设置。优先级和任务一样数字越大优先级越高。
协程优先级只与其他协程相关。如果在同一个应用程序中混合了任务和协程,那么任务的优先级始终比协程的优先级高。

2.4- 协程调度

协程是通过重复调用vCoRoutineSchedule() 来调度的。调用 vCoRoutineSchedule() 的最佳位置是从空闲任务钩子。即使您的应用程序只使用协程,也会出现这种现象,因为空闲任务仍将在调度程序启动时自动创建。

2.5- 协程和任务的混合

在空间任务中调度协程是允许任务和协程的混合的。这种方式只有当协程优先级低于空闲任务的优先级时,这种方式下才能执行。

2.5.1-局限性和复杂性

和任务相比来说,协程的好处是降低了RAM的使用空间,但是这些也会带来一定的限制。比如局限性以及复杂性。

2.5.2堆栈共享

当协程阻塞时,携程的堆栈时不会被保存的,这样即使在堆栈上有再多的变量,也会丢失。因此为了能够解决这个问题,需要声明一个在阻塞时保持调用的变量,作为静态。例如:

void vACoRoutineFunction( CoRoutineHandle_t xHandle,
                    UBaseType_t uxIndex )
{
static char c = 'a';

   // Co-routines must start with a call to crSTART().
   crSTART( xHandle );

   for( ;; )
   {
      // If we set c to equal 'b' here ...
      c = 'b';

      // ... then make a blocking call ...
      crDELAY( xHandle, 10 );

      // ... c will only be guaranteed to still 
      // equal 'b' here if it is declared static
      // (as it is here).
   }

   // Co-routines must end with a call to crEND().
   crEND();
}

堆栈共用的另一种结果是,可能导致协程阻塞API函数的调用只能来自于协程函数本身,而不是协程函数调用的函数。
例如:

void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
   // Co-routines must start with a call to crSTART().
   crSTART( xHandle );

   for( ;; )
   {
      // It is fine to make a blocking call here,
      crDELAY( xHandle, 10 );

      // but a blocking call cannot be made from within
      // vACalledFunction().
      vACalledFunction();
   }

   // Co-routines must end with a call to crEND().
   crEND();
}

void vACalledFunction( void )
{
   // Cannot make a blocking call here!
}

2.5.3 switch语句的应用

FreeRTOS文件中包含的默认协程实现不允许从switch语句中进行阻塞调用。

void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
   // Co-routines must start with a call to crSTART().
   crSTART( xHandle );

   for( ;; )
   {
      // It is fine to make a blocking call here,
      crDELAY( xHandle, 10 );

      switch( aVariable )
      {
         case 1 : // Cannot make a blocking call here!
                break;
         default: // Or here!
      }
   }

   // Co-routines must end with a call to crEND().
   crEND();
}

2.6协程例子

2.6.1 创建LED协程

void vFlashCoRoutine( CoRoutineHandle_t xHandle,
                 UBaseType_t uxIndex )
{
   // Co-routines must start with a call to crSTART().
   crSTART( xHandle );

   for( ;; )
   {
      // Delay for a fixed period.
      crDELAY( xHandle, 10 );

      // Flash an LED.
      vParTestToggleLED( 0 );
   }

   // Co-routines must end with a call to crEND().
   crEND();
}

2.6.2 协程调度

协同例程是通过重复调用 vCoRoutineSchedule()来调度的。执行此操作的最佳位置是从空闲任务中编写空闲任务挂钩。首先确保在FreeRTOSConfig.h 中将configUSE_IDLE_HOOK设置为 1。然后将空闲任务钩子编写为:

void vApplicationIdleHook( void )
{
   vCoRoutineSchedule( void );
}

或者,如果空闲任务不执行任何其他函数,从循环中调用vCoRoutineSchedule()会更有效:

void vApplicationIdleHook( void )
{
   for( ;; )
   {
      vCoRoutineSchedule( void );
   }
}

2.6.3 创建协程并启动RTOS调度

#include "task.h"
#include "croutine.h"

#define PRIORITY_0 0

void main( void )
{
   // In this case the index is not used and is passed 
   // in as 0.
   xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, 0 );

   // NOTE:  Tasks can also be created here!

   // Start the RTOS scheduler.
   vTaskStartScheduler();
}

2.6.4 扩展

现在假设我们要从同一个函数创建 8 个这样的协程。每个协程将闪烁不同的 LED 以不同的速率显示。index 参数可用于区分协程函数本身。

#include "task.h"
#include "croutine.h"

#define PRIORITY_0        0
#define NUM_COROUTINES    8

void main( void )
{
int i;

   for( i = 0; i < NUM_COROUTINES; i++ )
   {
      // This time i is passed in as the index.
      xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, i );
   }

   // NOTE: Tasks can also be created here!

   // Start the RTOS scheduler.
   vTaskStartScheduler();
}
还扩展了协程功能,因此每个程序都使用不同的LED和闪光率。
const int iFlashRates[ NUM_COROUTINES ] = { 10, 20, 30, 40, 50, 60, 70, 80 };
const int iLEDToFlash[ NUM_COROUTINES ] = { 0, 1, 2, 3, 4, 5, 6, 7 }

void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
{
   // Co-routines must start with a call to crSTART().
   crSTART( xHandle );

   for( ;; )
   {
      // Delay for a fixed period.  uxIndex is used to index into
      // the iFlashRates.  As each co-routine was created with
      // a different index value each will delay for a different
      // period.
      crDELAY( xHandle, iFlashRate[ uxIndex ] );

      // Flash an LED.  Again uxIndex is used as an array index,
      // this time to locate the LED that should be toggled.
      vParTestToggleLED( iLEDToFlash[ uxIndex ] );
   }

   // Co-routines must end with a call to crEND().
   crEND();
}

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

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

相关文章

MBA管理类联考英语二题型答题时间及次序问题

还有不到一个月时间&#xff0c;2023年MBA联考也进入到最后的收官阶段&#xff0c;这个阶段对于多数已经系统复习过的考生&#xff0c;一般需要进行通盘梳理备考&#xff0c;而不是专注于单个模块的复习。在做试卷或真题的过程中&#xff0c;如何才能更有利于分数这个问题需要大…

[附源码]Python计算机毕业设计Django电影院网上售票系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Mysql:sql去重的几种方式(大数据hive也可参考)

文章目录前言准备创建表测试数据目标探索distinct 去重group by 去重实现方案方案一方案二方案三前言 我们做数据分析的时候经常会遇到去重问题&#xff0c;下面总结 sql 去重的几种方式&#xff0c;后续如果还有再补充&#xff0c;大数据分析层面包括 hive、clickhouse 也可参…

TStor OneCOS 技术专栏——轻松单桶万亿

TStor OneCOS简介 TStor OneCOS海量对象存储&#xff08;后面简称OneCOS&#xff09;&#xff0c;是基于腾讯云公有云存储架构打造的完全自研的分布式软件定义存储&#xff0c;轻松支持单桶万亿对象和EB级容量&#xff0c;集群容量无限伸缩&#xff0c;同时支持高密大盘等多种…

【个人记录 | UNet | 整理ing】

【代码】 麋鹿 读后感&#xff1a; V1讲框架流程、V2V3狠真实,日常各种报错|预处理|size|格式|维度&#xff1b;“又出错了 狠棒狠棒 T T” 看V1脑袋有个框架&#xff0c;后面两个有较多设计预处理等报错.注意num_classes和weight_path V1&#xff08;视频教程&#xff09;、…

标记二肽Dansyl-Ala-Arg、87687-46-5

二肽Dansyl-Ala-Arg 编号&#xff1a;200087 CAS号&#xff1a;87687-46-5 三字母&#xff1a;Dansyl-Ala-Arg-COOH 描 述&#xff1a;羧肽酶 M 的荧光底物。由于底物和裂解产物 Dansyl-Ala-OH 具有同等荧光&#xff08;λex 340 nm&#xff1b;λem 495 nm&#xff09;&…

PyQt5安装详细教程

先展示一下安装好后的效果如下&#xff1a; 一、安装PyQt5 1、通过使用豆瓣镜像在命令提示符 (WINR)里输入cmd打开窗口进行安装&#xff1a; 点击确定后 输入pip install PyQt5 -i https://pypi.douban.com/simple&#xff0c;等待安装 当下载界面出现Successfully&#xff08…

[附源码]计算机毕业设计springboot良辰之境影视评鉴系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

小红书数据分析工具 | 新中式内容营销怎么做?

一句周杰伦的“国风就是最diao的”&#xff0c;让许多博主纵身涌入一片创作之海&#xff0c;吹起了暗藏在每一个中国人民心底的中国之风。新中式作为一直新锐队伍&#xff0c;发展潜力仍然很大&#xff0c;由于新中式风格所喜爱的人群是特定的&#xff0c;新中式服饰如何在小红…

吉时利2600A系列/2611A数字源表

2600A系列数字源表 吉时利最新的I-V源-测量仪器&#xff0c;既可以用作桌面级I-V特性分析工具&#xff0c;也可以成为多通道I-V测试系统的组 成部分。对于桌面级的应用&#xff0c;2600A系列提供一款嵌入式TSP Express测试软件&#xff0c;允许用户快速、方便地进行常 用的I-V测…

Kettle入门教程

目录 一、Kettle是什么 二、Kettle的两种设计 三、Kettle核心组件 四、安装与启动 五、使用 5.1 简单介绍 5.2 输入 5.3 输出 5.4 转换 5.5 脚本 一、Kettle是什么 Kettle最早是一个开源的ETL&#xff08;Extract-Transform-Load&#xff0c;数据仓库技术&#xff09…

[附源码]计算机毕业设计springboot基于Web的软考题库平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

8、多进程之间的通信

多进程之间的常用通信方法有两种&#xff0c;及Queue和Pipe 一、Queue Queue([maxsize])&#xff1a;创建共享的进程队列。maxsize是队列中允许的最大项数。如果省略此参数&#xff0c;则无大小限制。底层队列使用管道和锁定实现。另外&#xff0c;还需要运行支持线程以便队列中…

Docker网络模式之bridge-尚文网络xUP楠哥

~~全文共1572字&#xff0c;阅读需约5分钟。 进Q群11372462&#xff0c;领取专属报名福利&#xff0c;包含云计算学习路线图代表性实战训练大厂云计算面试题资料! 当docker已经启动后&#xff0c;会生成一个名字叫做docker0的虚拟网桥&#xff0c;给到一个默认的IP地址为172.1…

Databend 开源周报 #69

Databend 是一款强大的云数仓。专为弹性和高效设计&#xff0c;自由且开源。 即刻体验云服务&#xff1a;https://app.databend.com。 New Features multiple catalog 实现删除用户定义目录 (#8820) meta 新增用于删除 key 和使 key 过期的 cli 命令 (#8858) planner 支…

30组易混易错词汇辨析,柯桥成人英语培训哪家好

30组易混易错词汇辨析 1. clothes, cloth, clothing clothes统指各种衣服&#xff0c;谓语动词永远是复数&#xff0c; cloth指布&#xff0c;为不可数名词 clothing 服装的总称&#xff0c;指一件衣服用a piece of, an article of 2. amount, number amount后接不可数名词…

求Huffman树的带权路径长度

Huffman树的建立过程&#xff1a; 首先得到整个叶子结点的集合&#xff1a; 求Huffman树的带权路径长度算法&#xff1a; 书上讲常见的求Huffman树的带权路径长度算法为&#xff1a;从叶子结点权值乘路径长度&#xff1a; WPL7*25*25*23*32*349 另外一种求WPL的算法为&…

视频编解码学习之一:理论基础

1. 为什么要进行视频压缩&#xff1f; 未经压缩的数字视频的数据量巨大 存储困难 一张DVD只能存储几秒钟的未压缩数字视频。 传输困难 1兆的带宽传输一秒的数字电视视频需要大约4分钟。 \2. 为什么可以压缩 去除冗余信息 空间冗余&#xff1a;图像相邻像素之间有较强的相关性…

化工厂人员定位系统:以安全为出发点,助力企业安全生产管控数智化

化工厂人员定位系统采用先进的高精度时间同步技术和调度技术&#xff0c;可在复杂化工场景中精准锁定作业人员在多层空间内的实时位置&#xff0c;实现高精度人员定位。 如何管理好每个车间的作业人员&#xff1f; 如何监管作业人员是否按时到岗&#xff1f; 如何知晓当前人员…

阿里专家精心整理分享的Java程序员面试笔试通关宝典PDF

前言 学习是一种基础性的能力。然而&#xff0c;“吾生也有涯&#xff0c;而知也无涯。”&#xff0c;如果学习不注意方法&#xff0c;则会“以有涯随无涯&#xff0c;殆矣”。 学习就像吃饭睡觉一样&#xff0c;是人的一种本能&#xff0c;人人都有学习的能力。我们在刚出生…