FreeRtos入门-5 任务通知

在FreeRTOS中,任务通知、队列、信号量和事件组都是用于任务间通信和同步的机制,但它们各自具有不同的特性和适用场景。

任务通知的主要优势在于其高效性和明确性。使用任务通知发送事件或数据给某个任务时,效率更高,且可以明确指定通知哪个任务。此外,任务通知还更节省内存,因为使用它无需额外创建结构体。然而,任务通知的限制在于它不能向中断服务程序(ISR)发送数据,因为ISR并没有任务结构体。同时,任务通知发送的数据只能由指定的任务独享。

队列的特性在于它遵循先进先出(FIFO)的原则,具有有限容量,且其操作可以是阻塞的。队列常用于在任务之间传递数据,例如一个任务不断向队列中写入数据,另一个任务不断从队列中读取数据。

信号量主要用于实现任务之间的互斥和同步。二值信号量类似于互斥锁,用于确保在任何时刻只有一个任务能够访问关键资源。计数信号量则允许有更多状态,适用于多个任务对同一资源的并发访问。互斥信号量是二值信号量的一种特殊形式,用于确保在任何时刻只有一个任务能够执行临界区代码。

事件组则主要用于任务间的同步,可以简单理解为一个有多个bit位的整数,每一位都代表一个不同的事件。事件组具有“广播”作用,当某个事件发生时,会唤醒所有符合条件的任务。事件组只用于同步,不提供数据传输功能,且支持事件等待超时机制。

综上所述,任务通知、队列、信号量和事件组在FreeRTOS中各自扮演不同的角色,具有不同的特性和适用场景。选择使用哪种机制取决于具体的应用需求和目标。

1,区分之前的队列,信号量,事件组,任务通知不需要提前定义结构体。

2,任务通知有两对相关函数

使用ucNotifyState来切换任务的状态(阻塞,就绪)

使用ucNotifiedValue传递信息

3,函数原型:

1)xTaskNoitfyGive,ulTaskNotifyTake

任务A要发送任务B,任务B中有个值value

任务A使用xTaskNoitfyGive发送,他只有目标任务,没有目标值,通过让value++改变值

任务B通过ulTaskNotifyTake 去取Vlaue

2)xTaskNotify(TaskHandle xTaskToNotify,uint32_t ulvalue,eNotifyAction eAction ),ulTaskNotifyWait(uint32_t ulBitsToClearOnEntry,

uint32_t ulBitsToClearOnExit,

uint32_t * pulNotificationValue.

TickType_t xTicksToWait)

xTaskNotify(TaskHandle xTaskToNotify,uint32_t ulvalue,eNotifyAction eAction ),
ulTaskNotifyWait(uint32_t ulBitsToClearOnEntry,
                        uint32_t ulBitsToClearOnExit,
                        uint32_t * pulNotificationValue.
                        TickType_t xTicksToWait)

发送函数

作用

接收函数

作用

xTaskNotifyGive

val++

ulTaskNotifyTake

val-- 或 val = 0

xTaskNotify

xTaskNotifyWait

不使用val,只起通知作用

可以在函数进入时清除val的某些位可以在函数退出前清除val的某些位可以取得val的值

val |= (bits)

val++

val = xxx 不覆盖,当ucNotifyState表示在等待才起效

val = xxx覆盖

eNotifyAction参数说明:

eNotifyAction取值

说明

eNoAction

仅仅是更新通知状态为"pending",未使用ulValue。这个选项相当于轻量级的、更高效的二进制信号量。

eSetBits

通知值 = 原来的通知值 | ulValue,按位或。相当于轻量级的、更高效的事件组。

eIncrement

通知值 = 原来的通知值 + 1,未使用ulValue。相当于轻量级的、更高效的二进制信号量、计数型信号量。相当于xTaskNotifyGive()函数。

eSetValueWithoutOverwrite

不覆盖。如果通知状态为"pending"(表示有数据未读),则此次调用xTaskNotify不做任何事,返回pdFAIL。如果通知状态不是"pending"(表示没有新数据),则:通知值 = ulValue。

eSetValueWithOverwrite

覆盖。无论如何,不管通知状态是否为"pendng",通知值 = ulValue。

理论总结

  1. eAction=eNoAction,ulvalue不起作用,相当于轻量级,更高效二进制信号量
  2. eAction=eSetBits,通知值 = 原来的通知值 | ulValue,按位或。相当于轻量级的、更高效的事件组。
  3. eAction=eIncrement通知值 = 原来的通知值 + 1,未使用ulValue。相当于轻量级的、更高效的二进制信号量、计数型信号量。相当于xTaskNotifyGive()函数。

对于任务A发送数据后,如何通知任务B

ulTaskNotifyWait(uint32_t ulBitsToClearOnEntry,

uint32_t ulBitsToClearOnExit,

uint32_t * pulNotificationValue.

TickType_t xTicksToWait)

ulBitsToClearOnEntry ,在入口处:val &= ~(bits)在入口处清除所有位

ulBitsToClearOnExit,,在出口处:val &= ~(bits)在出口处清除所有位

pulNotificationValue 在出口被清楚前返回*pul = val

xTicksToWait 等待时间

任务通知-轻量级信号量

使用信号量

1,使用信号量-计数值实现任务1,take sum,sum++,任务2 give 10次,并打印take give 次数

void Task1Function(void *parm)
{
    int i= 0;
    while(1)
    {        
        for(i = 0;i<10;i++)
        {
            sum++;
            xSemaphoreGive(xSemCalc) ;//让信号量+1
            vTaskDelay(2);
        }     
        vTaskDelete(NULL); //take10 次后自杀
    }
}
 
void Task2Function(void *parm)
{
    int i = 0;
    while(1)
    {
        xSemaphoreTake(xSemCalc, portMAX_DELAY);
        printf("take time = %d,sum = %d\r\n",i++,sum);
    }
}

int main( void )
{
#ifdef DEBUG
  debug();
#endif

    prvSetupHardware();
    printf("Hello, world!\r\n");
    xSemCalc = xSemaphoreCreateCounting(10, 0);//计数最大值10,初始值0
    xTaskCreate(Task1Function,"task1",100,NULL,1,&Task1Handle);
    xTaskCreate(Task2Function,"task2",100,NULL,1,&Task2Handle);

    /* Start the scheduler. */
    vTaskStartScheduler();

    /* Will only get here if there was not enough heap space to create the
    idle task. */

替换成轻量级任务通知实现相同功能

void Task1Function(void *parm)
{
    int i= 0;
    
    while(1)
    {        
        for(i = 0;i<10;i++)
        {
            sum++;
            //xSemaphoreGive(xSemCalc) ;//让信号量+1
            xTaskNotifyGive(Task2Handle);
            vTaskDelay(5);
        }
        
        vTaskDelete(NULL); //take10 次后自杀
    }
}
void Task2Function(void *parm)
{
    int i = 0;
    int val = 0;
    while(1)
    {
    //    xSemaphoreTake(xSemCalc, portMAX_DELAY);
        val = ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
        printf("take time = %d,sum = %d,val = %d\r\n",i++,sum,val);
    }

}
int main( void )
{
#ifdef DEBUG
  debug();
#endif

    prvSetupHardware();

    printf("Hello, world!\r\n");
 // xSemCalc = xSemaphoreCreateCounting(10, 0);//计数最大值10,初始值0

    
    xTaskCreate(Task1Function,"task1",100,NULL,1,&Task1Handle);
    xTaskCreate(Task2Function,"task2",100,NULL,1,&Task2Handle);

    /* Start the scheduler. */
    vTaskStartScheduler();

    /* Will only get here if there was not enough heap space to create the
    idle task. */
    return 0;
}

对比

信号量-计数

任务通知-轻量级信号量

创建

xSemCalc = xSemaphoreCreateCounting(10, 0);//计数最大值10,初始值0

/

give

xSemaphoreGive(xSemCalc) ;//让信号量+1

xTaskNotifyGive(Task2Handle);

take

xSemaphoreTake(xSemCalc, portMAX_DELAY);

val = ulTaskNotifyTake(pdFALSE, portMAX_DELAY);

//pdFALSE,退出不清除val,pdTure,退出清除val

总结

1,任务通知不需要创建结构体。参数传递通过句柄通知。(task1通知task2)

任务通知-轻量级队列

队列

使用任务通知实现队列

创建

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );

发送

BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );

接收

BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );

1,使用传统队列实现任务1,10次,任务2 读10次

void Task1Function(void *parm)
{
    int i= 0;
    while(1)
    {        
        for(i = 0;i<10;i++)
        {
            sum++;
            xQueueSendToBack(xQueueCalc,&sum,portMAX_DELAY);
            vTaskDelay(5);
        }
        vTaskDelete(NULL); //take10 次后自杀
    }
}
 
void Task2Function(void *parm)
{
    int i = 0;
    int val = 0;
    while(1)
    {
        xQueueReceive(xQueueCalc,&val,portMAX_DELAY);
        printf("take time = %d,sum = %d,val = %d\r\n",i++,sum,val);
        
    }
}
int main( void )
{
#ifdef DEBUG
  debug();
#endif

    prvSetupHardware();

    printf("Hello, world!\r\n");

    xQueueCalc = xQueueCreate(1, sizeof(uint32_t));
    
    xTaskCreate(Task1Function,"task1",100,NULL,1,&Task1Handle);
    xTaskCreate(Task2Function,"task2",100,NULL,1,&Task2Handle);

    /* Start the scheduler. */
    vTaskStartScheduler();

    /* Will only get here if there was not enough heap space to create the
    idle task. */
    return 0;
}

2,替换成轻量级任务通知实现相同功能

void Task1Function(void *parm)
{
    int i= 0;
    while(1)
    {        
        for(i = 0;i<10;i++)
        {
            sum++;
            //xQueueSendToBack(xQueueCalc,&sum,portMAX_DELAY);
            xTaskNotify(Task2Handle,sum,eSetValueWithoutOverwrite);//
            vTaskDelay(5);
        }
        vTaskDelete(NULL); //take10 次后自杀
    }
}

void Task2Function(void *parm)
{
    uint32_t i = 0;
    uint32_t val = 0;
    while(1)
    {
        //xQueueReceive(xQueueCalc,&val,portMAX_DELAY);
        xTaskNotifyWait(0,0,&val,portMAX_DELAY);
        printf("take time = %d,sum = %d,val = %d\r\n",i++,sum,val);
        
    }

}
int main( void )
{
#ifdef DEBUG
  debug();
#endif

    prvSetupHardware();

    printf("Hello, world!\r\n");

    //xQueueCalc = xQueueCreate(1, sizeof(uint32_t));
    
    xTaskCreate(Task1Function,"task1",100,NULL,1,&Task1Handle);
    xTaskCreate(Task2Function,"task2",100,NULL,1,&Task2Handle);

    /* Start the scheduler. */
    vTaskStartScheduler();

    /* Will only get here if there was not enough heap space to create the
    idle task. */
    r

总结:轻量级任务通知只能存放一个val值,要尽快take出来,否则要么被覆盖,要么不覆盖阻塞

任务通知-轻量级事件组

事件组

使用任务通知实现事件组

创建

EventGroupHandle_t xEventGroupCreate( void )

设置事件

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );

BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );

等待事件

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait );

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );

1,传统的事件组实现

任务1,sum++,加完设置bit0,

任务2,dec--,加完设置bit1,

任务3,判断bit0,bit1 都完成后,打印val1,val2

void Task1Function(void * param)
{
    volatile int i = 0;
    while (1)
    {
        for (i = 0; i < 100000; i++)
            sum++;
         xQueueSend(xQueueCalcHandle, &sum, 0);
        /* 设置事件0 */
        xEventGroupSetBits(xEventGroupCalc, (1<<0));

        vTaskDelete(NULL);
    }
}
void Task2Function(void * param)
{
    volatile int i = 0;
    while (1)
    {
        for (i = 0; i < 1000000; i++)
            dec--;
        xQueueSend(xQueueCalcHandle, &dec, 0);
        /* 设置事件1 */
        xEventGroupSetBits(xEventGroupCalc, (1<<1));

        vTaskDelete(NULL);
    }
}
void Task3Function(void * param)
{
    int val1, val2;

    while (1)
    {
        /*等待事件  */
            xEventGroupWaitBits(xEventGroupCalc, (1<<0)|(1<<1), pdTRUE, pdTRUE, portMAX_DELAY);
            xQueueReceive(xQueueCalcHandle, &val1, 0);
            xQueueReceive(xQueueCalcHandle, &val2, 0);
        
            printf("val1 = %d, val2 = %d\r\n", val1, val2);
 
    }
}
int main( void )
{
    TaskHandle_t xHandleTask1;
        
#ifdef DEBUG
  debug();
#endif

    prvSetupHardware();

    printf("Hello, world!\r\n");

    /* 创建事件组 */
    xEventGroupCalc = xEventGroupCreate();

    xQueueCalcHandle = xQueueCreate(2, sizeof(int));
    if (xQueueCalcHandle == NULL)
    {
        printf("can not create queue\r\n");
    }


    xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
    xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
    xTaskCreate(Task3Function, "Task3", 100, NULL, 1, &xHandleTask3);
    /* Start the scheduler. */
    vTaskStartScheduler();

    /* Will only get here if there was not enough heap space to create the
    idle task. */
    return 0;
}

2,使用轻量级事件组替代

void Task1Function(void * param)
{
    volatile int i = 0;
    while (1)
    {
        for (i = 0; i < 100000; i++)
            sum++;
        xQueueSend(xQueueCalcHandle, &sum, 0);
        /* 设置事件0 */
        //xEventGroupSetBits(xEventGroupCalc, (1<<0));
        xTaskNotify(xHandleTask3, (1<<0), eSetBits);
        printf("Task 1 set bit 0\r\n");
        vTaskDelete(NULL);
    }
}
void Task2Function(void * param)
{
    volatile int i = 0;
    while (1)
    {
        for (i = 0; i < 1000000; i++)
            dec--;
        xQueueSend(xQueueCalcHandle, &dec, 0);
        /* 设置事件1 */
        //xEventGroupSetBits(xEventGroupCalc, (1<<1));
        xTaskNotify(xHandleTask3, (1<<1), eSetBits);
        printf("Task 2 set bit 1\r\n");
        vTaskDelete(NULL);
    }
}
void Task3Function(void * param)
{
    int val1, val2;
    int bits;
    while (1)
    {
        /*等待事件  */
        //xEventGroupWaitBits(xEventGroupCalc, (1<<0)|(1<<1), pdTRUE, pdTRUE, portMAX_DELAY);
        xTaskNotifyWait(0, 0, &bits, portMAX_DELAY);
        if ((bits & 0x3) == 0x3)
        {
            vTaskDelay(20);
            xQueueReceive(xQueueCalcHandle, &val1, 0);
            xQueueReceive(xQueueCalcHandle, &val2, 0);
            
            printf("val1 = %d, val2 = %d\r\n", val1, val2);
        }
        else
        {
            vTaskDelay(20);
            printf("have not get all bits, get only 0x%x\r\n", bits);
        }
    }
}
int main( void )
{
    TaskHandle_t xHandleTask1;
        
#ifdef DEBUG
  debug();
#endif

    prvSetupHardware();

    printf("Hello, world!\r\n");

    /* 创建事件组 */
    xEventGroupCalc = xEventGroupCreate();

    xQueueCalcHandle = xQueueCreate(2, sizeof(int));
    if (xQueueCalcHandle == NULL)
    {
        printf("can not create queue\r\n");
    }


    xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
    xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
    xTaskCreate(Task3Function, "Task3", 100, NULL, 1, &xHandleTask3);
    /* Start the scheduler. */
    vTaskStartScheduler();

    /* Will only get here if there was not enough heap space to create the
    idle task. */
    return 0;
}

总结

1,使用轻量级任务通知实现事件组只要在任务1,2中,xTaskNotify(任务3句柄) ,不管哪些位触发,都会唤醒任务3句柄中的任务。即使没有全部位触发,也会使任务3唤醒

这样进入任务3后,需要判断是否是需要满足的位达到再进入操作。

2,传统的事件组,在处理任务中的take 函数里,可以指定一个位满足,或者全部满足。

比轻量级任务通知实现事件组 多个全部满足的条件。

如果是单独指定一个位满足唤醒,进去后也可以单独在判断一次 是哪些位触发了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Tuxera2023 NTFS for Mac下载,安装和序列号激活

对于必须在Windows电脑和Mac电脑之间来回切换的Mac朋友来说&#xff0c;跨平台不兼容一直是一个巨大的障碍&#xff0c;尤其是当我们需要使用NTFS格式的硬盘在Windows和macOS之间共享文件时。因为Mac默认不支持写入NTFS磁盘。 为了解决这一问题&#xff0c;很多朋友会选择很便捷…

linux操作系统安装及命令初识,上岸蚂蚁金服

310 包&#xff09; desktop 1800个包左右 内容必须大于 768M 系统设置 分区设置 挂载点 /boot / swap 交换分区–占用磁盘容量 网络配置 网卡配置 设置为ON 主机名配置 Begin installation 设置 root 用户密码 命令初识 命令 选项 参数&#xff1a; 命令选项参数…

Restful Web Service

Restful 1.特点 RESTful是一种架构风格&#xff0c;强调简单、轻量级和对资源的状态less操作。RESTful是通过HTTP协议进行通信的。RESTful的应用程序可以调用运行在不同服务器上的服务或函数。RESTful的接口通常使用JSON&#xff0c;但实际上它们都支持多种数据格式。RESTful…

Trace链异常检测汇总

微服务应用与单块应用完全不同&#xff0c;一个微服务系统少则有几十个微服务组成&#xff0c;多则可能有上百个服务。比如BAT级别的互联网公司&#xff0c;一般都超过上百个服务&#xff0c;服务之间的依赖关系错综复杂&#xff0c;如果没有有效的监控手段&#xff0c;那么出现…

风控系统之普通规则条件,使用LiteFlow实现

个人博客&#xff1a;无奈何杨&#xff08;wnhyang&#xff09; 个人语雀&#xff1a;wnhyang 共享语雀&#xff1a;在线知识共享 Github&#xff1a;wnhyang - Overview 提要 参考&#xff1a;智能风控筑基手册&#xff1a;全面了解风控决策引擎 前面有可配置输入参数的接…

Gson的用法

1. 导入依赖 <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.6</version> </dependency> 2. 使用Gson进行解析 2.1 Gson解析普通对象 package com.jiang.partnetbackend.…

六、企业级架构缓存篇之memcached

一、memcached概述 1、网站架构优化流程&#xff1a; LNMP架构中网站应用访问流程&#xff1a; 浏览器 (app) → web 服务器 → 后端服务 (php) → 数据库 (mysql) 访问流程越多&#xff0c;访问速度越慢&#xff0c;出现问题的几率也越大。 网站访问流程优化思路&#xff1…

软件测试(测试用例详解)(三)

1. 测试用例的概念 测试用例&#xff08;Test Case&#xff09;是为了实施测试而向被测试的系统提供的一组集合。 测试环境操作步骤测试数据预取结果 测试用例的评价标准&#xff1a; 用例表达清楚&#xff0c;无二义性。。用例可操作性强。用例的输入与输出明确。一条用例只有…

c语言之向main函数传递参数

在c语言中&#xff0c;main函数也是可以传递传递参数的&#xff0c;业内向main函数传递参数的格式是 main(int argc,char *argv[]) 向main函数传递参数不是通过代码传递的&#xff0c;一般是通过dos命令传递 举个例子 #include<stdio.h> void main(int argc,char *ar…

算法刷题应用知识补充--基础算法、数据结构篇

这里写目录标题 位运算&#xff08;均是拷贝运算&#xff0c;不会影响原数据&#xff0c;这点要注意&#xff09;&、|、^位运算特性细节知识补充对于n-1的理解异或来实现数字交换找到只出现一次的数据&#xff0c;其余数据出现偶数次 >> 、<<二进制中相邻的位的…

算法设计与分析实验报告c++实现(排序算法、三壶谜题、交替放置的碟子、带锁的门)

一、实验目的 1&#xff0e;加深学生对分治法算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、 编…

为什么mac文件拖拽不了 mac文件拖不进硬盘里 macbookpro文件无法拖进移动硬盘 Tuxera NTFS for Mac 2023绿色

如果你是一位Mac用户&#xff0c;你可能会遇到这样的问题&#xff1a;你想把Mac上的文件拖拽到其他位置&#xff0c;比如桌面、文件夹或者外接硬盘&#xff0c;但是却发现无法操作&#xff0c;这是为什么呢&#xff1f;这篇文章将为你解答为什么mac文件拖拽不了&#xff0c;以及…

Web安全-浏览器安全策略及跨站脚本攻击与请求伪造漏洞原理

Web安全-浏览器安全策略及跨站脚本攻击与请求伪造漏洞原理 Web服务组件分层概念 静态层 &#xff1a;web前端框架&#xff1a;Bootstrap&#xff0c;jQuery,HTML5框架等&#xff0c;主要存在跨站脚本攻击脚本层&#xff1a;web应用&#xff0c;web开发框架&#xff0c;web服务…

Linux从入门到精通 --- 2.基本命令入门

文章目录 第二章&#xff1a;2.1 Linux的目录结构2.1.1 路径描述方式 2.2 Linux命令入门2.2.1 Linux命令基础格式2.2.2 ls命令2.2.3 ls命令的参数和选项2.2.4 ls命令选项的组合使用 2.3 目录切换相关命令2.3.1 cd切换工作目录2.3.2 pwd查看当前工作目录2.4 相对路径、绝对路径和…

vue2+elementUi的两个el-date-picker日期组件进行联动

vue2elementUi的两个el-date-picker日期组件进行联动 <template><el-form><el-form-item label"起始日期"><el-date-picker v-model"form.startTime" change"startTimeChange" :picker-options"startTimePickerOption…

c# wpf template itemtemplate+ListBox

1.概要 2.代码 <Window x:Class"WpfApp2.Window7"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend/…

【opencv】示例 3calibration.cpp 利用OpenCV库进行三路相机校准

此代码是一个利用OpenCV库进行三路相机校准的C程序。这个示例程序主要用于校准水平摆放的三台相机。 以下是关键函数及其功能的简要总结&#xff1a; help(char** argv): 显示程序的使用方法。calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>&…

Vue 事件处理 -- 事件修饰符(prevent、stop、capture、self、once)

1. 事件修饰符 Vue中的事件修饰符&#xff1a; prevent&#xff1a;阻止默认事件&#xff08;常用&#xff09;&#xff1b;stop&#xff1a;阻止事件冒泡&#xff08;常用&#xff09;&#xff1b;once&#xff1a;事件只触发一次&#xff08;常用&#xff09;&#xff1b;cap…

软考 系统架构设计师系列知识点之数据库基本概念(1)

所属章节&#xff1a; 第6章. 数据库设计基础知识 第1节 数据库基本概念 数据&#xff08;Data&#xff09;是描述事务的符号记录&#xff0c;它具有多种表现形式&#xff0c;可以是文字、图形、图像、声音和语言等。信息&#xff08;Information&#xff09;是现实世界事物的…

考研回忆录【二本->211】

备考时长差不多快一年半&#xff0c;从22年的11月底开始陆陆续续地准备考研&#xff0c;因为开始的早所以整个备考过程显得压力不是很大&#xff0c;中途还去一些地方旅游&#xff0c;我不喜欢把自己绷得太紧。虽然考的不是很好&#xff0c;考完我甚至都没准备复试&#xff0c;…