当前位置: 首页 > news >正文

FrereRTOS事件组

文章目录

  • 一、事件组概念与操作
    • 1、事件组的概念
    • 2、事件组的操作
  • 二、事件组函数
    • 1、创建
    • 2、删除
    • 3、设置事件
    • 4、等待事件
    • 5、同步点
  • 三、示例:广播
  • 四、示例:等待一个任意事件
  • 五、示例: 等待多个事件都发生

学校组织秋游,组长在等待:

  • 张三:我到了
  • 李四:我到了
  • 王五:我到了
  • 组长说:好,大家都到齐了,出发!

秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的。

在这个日常生活场景中:

  • 出发:要等待这3个人都到齐,他们是"与"的关系
  • 交报告:只需等待这3人中的任何一个,他们是"或"的关系

在FreeRTOS中,可以使用事件组(event group)来解决这些问题。

本章涉及如下内容:

  • 事件组的概念与操作函数
  • 事件组的优缺点
  • 怎么设置、等待、清除事件组中的位
  • 使用事件组来同步多个任务

一、事件组概念与操作

1、事件组的概念

事件组可以简单地认为就是一个整数:

  • 每一位表示一个事件
  • 每一位事件的含义由程序员决定,比如:Bit0表示用来串口是否就绪,Bit1表示按键是否被按下
  • 这些位,值为1表示事件发生了,值为0表示事件没发生
  • 一个或多个任务、ISR都可以去写这些位;一个或多个任务、ISR都可以去读这些位
  • 可以等待某一位、某些位中的任意一个,也可以等待多位

image

事件组用一个整数来表示,其中的高8位留给内核使用,只能用其他的位来表示事件。那么这个整数是多少位的?

  • 如果configUSE_16_BIT_TICKS是1,那么这个整数就是16位的,低8位用来表示事件
  • 如果configUSE_16_BIT_TICKS是0,那么这个整数就是32位的,低24位用来表示事件
  • 如果configUSE_16_BIT_TICKS是用来表示Tick Count的,怎么会影响事件组?这只是基于效率来考虑
  • 如果configUSE_16_BIT_TICKS是1,就表示该处理器使用16位更高效,所以事件组也使用16位
  • 如果configUSE_16_BIT_TICKS是0,就表示该处理器使用32位更高效,所以事件组也使用32位

2、事件组的操作

事件组和队列、信号量等不太一样,主要集中在2个地方:

  • 唤醒谁?
    • 队列、信号量:事件发生时,只会唤醒一个任务
    • 事件组:事件发生时,会唤醒所有符号条件的任务,简单地说它有"广播"的作用
  • 是否清除事件?
    • 队列、信号量:是消耗型的资源,队列的数据被读走就没了;信号量被获取后就减少了
    • 事件组:被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件

以上图为列,事件组的常规操作如下:

  • 先创建事件组
  • 任务C、D等待事件:
    • 等待什么事件?可以等待某一位、某些位中的任意一个,也可以等待多位。简单地说就是"或"、"与"的关系。
    • 得到事件时,要不要清除?可选择清除、不清除。
  • 任务A、B产生事件:设置事件组里的某一位、某些位

二、事件组函数

1、创建

使用事件组之前,要先创建,得到一个句柄;使用事件组时,要使用句柄来表明使用哪个事件组。

有两种创建方法:动态分配内存、静态分配内存。函数原型如下:

/* 创建一个事件组,返回它的句柄。* 此函数内部会分配事件组结构体 * 返回值: 返回句柄,非NULL表示成功*/
EventGroupHandle_t xEventGroupCreate( void );/* 创建一个事件组,返回它的句柄。* 此函数无需动态分配内存,所以需要先有一个StaticEventGroup_t结构体,并传入它的指针* 返回值: 返回句柄,非NULL表示成功*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer );

2、删除

对于动态创建的事件组,不再需要它们时,可以删除它们以回收内存。

vEventGroupDelete可以用来删除事件组,函数原型如下:

/** xEventGroup: 事件组句柄,你要删除哪个事件组*/
void vEventGroupDelete( EventGroupHandle_t xEventGroup )

3、设置事件

可以设置事件组的某个位、某些位,使用的函数有2个:

  • 在任务中使用xEventGroupSetBits()
  • 在ISR中使用xEventGroupSetBitsFromISR()

有一个或多个任务在等待事件,如果这些事件符合这些任务的期望,那么任务还会被唤醒。

函数原型如下:

/* 设置事件组中的位* xEventGroup: 哪个事件组* uxBitsToSet: 设置哪些位? *              如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1*               可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0* 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了)*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet );/* 设置事件组中的位* xEventGroup: 哪个事件组* uxBitsToSet: 设置哪些位? *              如果uxBitsToSet的bitX, bitY为1, 那么事件组中的bitX, bitY被设置为1*               可以用来设置多个位,比如 0x15 就表示设置bit4, bit2, bit0* pxHigherPriorityTaskWoken: 有没有导致更高优先级的任务进入就绪态? pdTRUE-有, pdFALSE-没有* 返回值: pdPASS-成功, pdFALSE-失败*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,BaseType_t * pxHigherPriorityTaskWoken );

值得注意的是,ISR中的函数,比如队列函数xQueueSendToBackFromISR、信号量函数xSemaphoreGiveFromISR,它们会唤醒某个任务,最多只会唤醒1个任务。

但是设置事件组时,有可能导致多个任务被唤醒,这会带来很大的不确定性。所以xEventGroupSetBitsFromISR函数不是直接去设置事件组,而是给一个FreeRTOS后台任务(daemon task)发送队列数据,由这个任务来设置事件组。

如果后台任务的优先级比当前被中断的任务优先级高,xEventGroupSetBitsFromISR会设置**pxHigherPriorityTaskWoken*为pdTRUE。

如果daemon task成功地把队列数据发送给了后台任务,那么xEventGroupSetBitsFromISR的返回值就是pdPASS。

4、等待事件

使用xEventGroupWaitBits来等待事件,可以等待某一位、某些位中的任意一个,也可以等待多位;等到期望的事件后,还可以清除某些位。

函数原型如下:

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

先引入一个概念:unblock condition一个任务在等待事件发生时,它处于阻塞状态;当期望的时间发生时,这个状态就叫"unblock condition",非阻塞条件,或称为"非阻塞条件成立";当"非阻塞条件成立"后,该任务就可以变为就绪态

函数参数说明列表如下:

参数说明
xEventGroup等待哪个事件组?
uxBitsToWaitFor等待哪些位?哪些位要被测试?
xWaitForAllBits怎么测试?是"AND"还是"OR"?
pdTRUE: 等待的位,全部为1;
pdFALSE: 等待的位,某一个为1即可
xClearOnExit函数提出前是否要清除事件?
pdTRUE: 清除uxBitsToWaitFor指定的位
pdFALSE: 不清除
xTicksToWait如果期待的事件未发生,阻塞多久。
可以设置为0:判断后即刻返回;
可设置为portMAX_DELAY:一定等到成功才返回;
可以设置为期望的Tick Count,一般用*pdMS_TO_TICKS()*把ms转换为Tick Count
返回值返回的是事件值,
如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值;
如果是超时退出,返回的是超时时刻的事件值。

举例如下:

事件组的值uxBitsToWaitForxWaitForAllBits说明
01000101pdTRUE任务期望bit0,bit2都为1,
当前值只有bit2满足,任务进入阻塞态;
当事件组中bit0,bit2都为1时退出阻塞态
01000110pdFALSE任务期望bit1,bit2某一个为1, 当前值满足,所以任务成功退出
01000110pdTRUE任务期望bit1,bit2都为1,
当前值不满足,任务进入阻塞态;
当事件组中bit1,bit2都为1时退出阻塞态

你可以使用*xEventGroupWaitBits()等待期望的事件,它发生之后再使用xEventGroupClearBits()*来清除。但是这两个函数之间,有可能被其他任务或中断抢占,它们可能会修改事件组。

可以使用设置xClearOnExit为pdTRUE,使得对事件组的测试、清零都在*xEventGroupWaitBits()*函数内部完成,这是一个原子操作。

5、同步点

有一个事情需要多个任务协同,比如:

  • 任务A:炒菜
  • 任务B:买酒
  • 任务C:摆台
  • A、B、C做好自己的事后,还要等别人做完;大家一起做完,才可开饭

使用*xEventGroupSync()*函数可以同步多个任务:

  • 可以设置某位、某些位,表示自己做了什么事
  • 可以等待某位、某些位,表示要等等其他任务
  • 期望的时间发生后,*xEventGroupSync()*才会成功返回
  • xEventGroupSync成功返回后,会清除事件

xEventGroupSync函数原型如下:

EventBits_t xEventGroupSync(    EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet,const EventBits_t uxBitsToWaitFor,TickType_t xTicksToWait );

参数列表如下:

参数说明
xEventGroup哪个事件组?
uxBitsToSet要设置哪些事件?我完成了哪些事件?
比如0x05(二进制为0101)会导致事件组的bit0,bit2被设置为1
uxBitsToWaitFor等待那个位、哪些位?
比如0x15(二级制10101),表示要等待bit0,bit2,bit4都为1
xTicksToWait如果期待的事件未发生,阻塞多久。
可以设置为0:判断后即刻返回;
可设置为portMAX_DELAY:一定等到成功才返回;
可以设置为期望的Tick Count,一般用*pdMS_TO_TICKS()*把ms转换为Tick Count
返回值返回的是事件值,
如果期待的事件发生了,返回的是"非阻塞条件成立"时的事件值;
如果是超时退出,返回的是超时时刻的事件值。

三、示例:广播

本节代码为:23_eventgroup_broadcast,主要看nwatch\game2.c。

car1运行到终点后,会设置bit0事件;car2、car3都等待bit0事件。car1设置bit0事件时,会通知到car2、car3,这就是一个广播作用。

创建事件组,代码如下:

void car_game(void)
{int i,j;int x;g_framebuffer = LCD_GetFrameBuffer(&g_xres, &g_yres, &g_bpp);draw_init();draw_end();xEventCar = xEventGroupCreate();//创建事件组/* 绘制路标	*/for(i=0;i<3;i++){for(j=0;j<8;j++){draw_bitmap(16*j, 16+17*i, roadMarking, 8, 1, NOINVERT, 0);draw_flushArea(16*j, 16+17*i, 8, 1);		}}#if 0/* 显示三辆小车 */for(i=0;i<3;i++){draw_bitmap(cars[i].x, cars[i].y, carImg, 15, 16, NOINVERT, 0);draw_flushArea(cars[i].x, cars[i].y, 15, 16);	}
#endifxTaskCreate(car1_task, "car1task", 128, &cars[0], osPriorityNormal, NULL);	xTaskCreate(car2_task, "car2task", 128, &cars[1], osPriorityNormal+2, NULL);	xTaskCreate(car3_task, "car3task", 128, &cars[2], osPriorityNormal+2, NULL);	//car2和car3优先级一样后 car1到达最右边后设置事件组 car2和car3得到事件组后一起运行 若优先级不同 则优先级高的先运行 到最右边后再到另一个运行
}

car2等待事件,代码如下:

void car2_task(void *params)
{struct car *car = params;struct ir_Data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10,sizeof(struct ir_Data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 初始化小车 */ShowCar(car);/* 等待bit0事件 */xEventGroupWaitBits(xEventCar,(1<<0),pdTRUE,pdFALSE,portMAX_DELAY);while(1){
//		/* 读取按键值  */
//		xQueueReceive(xQueueIR,&idata,portMAX_DELAY);//		/* 控制汽车往右移动 */
//		if(idata.data == car->control_key)
//		{if(car->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(car);/* 调整位置 */car->x += 1	;//每次按下右移5个单位if(car->x > g_xres - CAR_LENGTH)//超过屏幕分辨率(128)car->x = g_xres - CAR_LENGTH;//到达最大位置处/* 重新显示汽车 */ShowCar(car);/* 这里的delay函数主要是小车的显示延时频率 调用vTaskDelay为阻塞状态 会卡死等待 当执行到调用vTaskDelay的任务时 其他任务能正常运行 调用mdelay则会占用CPU资源 当执行调用mdelay的任务时 其他低优先级任务无法得以运行*///vTaskDelay(50);mdelay(50 );if(car->x == g_xres - CAR_LENGTH){/* 汽车到达最右边 释放信号量 *///xSemaphoreGive(xSemTicks);//car2没有获取信号量 所以当其运行完毕自杀后car1继续运行vTaskDelete(NULL);}}
//		}}
}

car3等待事件,代码如下:

void car3_task(void *params)
{struct car *car = params;struct ir_Data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10,sizeof(struct ir_Data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 初始化小车 */ShowCar(car);/* 等待bit0事件 */xEventGroupWaitBits(xEventCar,(1<<0),pdTRUE,pdFALSE,portMAX_DELAY);while(1){
//		/* 读取按键值  */
//		xQueueReceive(xQueueIR,&idata,portMAX_DELAY);//		/* 控制汽车往右移动 */
//		if(idata.data == car->control_key)
//		{if(car->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(car);/* 调整位置 */car->x += 1	;//每次按下右移5个单位if(car->x > g_xres - CAR_LENGTH)//超过屏幕分辨率(128)car->x = g_xres - CAR_LENGTH;//到达最大位置处/* 重新显示汽车 */ShowCar(car);//vTaskDelay(50);mdelay(50 );if(car->x == g_xres - CAR_LENGTH){/* 汽车到达最右边 释放信号量 *///xSemaphoreGive(xSemTicks);vTaskDelete(NULL);}}
//		}}
}

car1运行到终点后,设置事件,代码如下:

void car1_task(void *params)
{struct car *car = params;struct ir_Data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10,sizeof(struct ir_Data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 初始化小车 */ShowCar(car);while(1){
//		/* 读取按键值  */
//		xQueueReceive(xQueueIR,&idata,portMAX_DELAY);//		/* 控制汽车往右移动 */
//		if(idata.data == car->control_key)
//		{if(car->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(car);/* 调整位置 */car->x += 1	;//每次按下右移5个单位if(car->x > g_xres - CAR_LENGTH)//超过屏幕分辨率(128)car->x = g_xres - CAR_LENGTH;//到达最大位置处/* 重新显示汽车 */ShowCar(car);vTaskDelay(50);if(car->x == g_xres - CAR_LENGTH){/* 汽车到达最右边 释放信号量 *///xSemaphoreGive(xSemTicks);/* 设置bit0 事件组 */xEventGroupSetBits(xEventCar,(1<<0));vTaskDelete(NULL);}}
//		}}
}

实验现象:car1运行到终点后,car2、car3同时启动。

四、示例:等待一个任意事件

本节代码为:24_eventgroup_or,主要看nwatch\game2.c。

car1运行到终点后,会设置bit0事件;car2运行到终点后,会设置bit1事件;car3等待bit0、bit1的任意一个事件

car1运行到终点后,设置事件,代码如下:

car1运行到终点后,设置事件,代码如下:

void car1_task(void *params)
{struct car *car = params;struct ir_Data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10,sizeof(struct ir_Data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 初始化小车 */ShowCar(car);/* 获得信号量 *///xSemaphoreTake(xSemTicks,portMAX_DELAY);//car1获得信号量开始运行while(1){
//		/* 读取按键值  */
//		xQueueReceive(xQueueIR,&idata,portMAX_DELAY);//		/* 控制汽车往右移动 */
//		if(idata.data == car->control_key)
//		{if(car->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(car);/* 调整位置 */car->x += 1	;//每次按下右移5个单位if(car->x > g_xres - CAR_LENGTH)//超过屏幕分辨率(128)car->x = g_xres - CAR_LENGTH;//到达最大位置处/* 重新显示汽车 */ShowCar(car);vTaskDelay(50);//50ms后开始运行if(car->x == g_xres - CAR_LENGTH){/* 汽车到达最右边 释放信号量 *///xSemaphoreGive(xSemTicks);/* 设置bit0 事件组 */xEventGroupSetBits(xEventCar,(1<<0));vTaskDelete(NULL);}}
//		}}
}

car2等待事件,代码如下:

void car2_task(void *params)
{struct car *car = params;struct ir_Data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10,sizeof(struct ir_Data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 初始化小车 */ShowCar(car);/* 获得信号量 *///xSemaphoreTake(xSemTicks,portMAX_DELAY);/* 等待bit0事件 */
//	xEventGroupWaitBits(xEventCar,(1<<0),pdTRUE,pdFALSE,portMAX_DELAY);while(1){
//		/* 读取按键值  */
//		xQueueReceive(xQueueIR,&idata,portMAX_DELAY);//		/* 控制汽车往右移动 */
//		if(idata.data == car->control_key)
//		{if(car->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(car);/* 调整位置 */car->x += 1	;//每次按下右移5个单位if(car->x > g_xres - CAR_LENGTH)//超过屏幕分辨率(128)car->x = g_xres - CAR_LENGTH;//到达最大位置处/* 重新显示汽车 */ShowCar(car);vTaskDelay(20);//20ms后开始运行//mdelay(50 );if(car->x == g_xres - CAR_LENGTH){/* 汽车到达最右边 释放信号量 *///xSemaphoreGive(xSemTicks);//car2没有获取信号量 所以当其运行完毕自杀后car1继续运行/* 设置bit1 事件组 */xEventGroupSetBits(xEventCar,(1<<1));vTaskDelete(NULL);}}
//		}}
}

car3等待bit0、bit1事件,实验“或”的关系(倒数第2个参数),代码如下:

void car3_task(void *params)
{struct car *car = params;struct ir_Data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10,sizeof(struct ir_Data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 初始化小车 */ShowCar(car);/* 获得信号量 *///xSemaphoreTake(xSemTicks,portMAX_DELAY);/* 等待bit0 or bit1事件(or或者and取决于第四个参数 pdFLASE为or pdTRUE为and) *//* 若这里是or 当car1先到时释放事件bit0 此时car3等到事件组则开始运行 car2停止运行 直到car3运行完毕 才到car2继续运行 *//* 若这里是and 必须car1和car2运行完毕释放bit哦和bit1事件后car3才能运行	*/xEventGroupWaitBits(xEventCar,(1<<0)|(1<<1),pdTRUE,pdTRUE,portMAX_DELAY);while(1){
//		/* 读取按键值  */
//		xQueueReceive(xQueueIR,&idata,portMAX_DELAY);//		/* 控制汽车往右移动 */
//		if(idata.data == car->control_key)
//		{if(car->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(car);/* 调整位置 */car->x += 1	;//每次按下右移5个单位if(car->x > g_xres - CAR_LENGTH)//超过屏幕分辨率(128)car->x = g_xres - CAR_LENGTH;//到达最大位置处/* 重新显示汽车 */ShowCar(car);//vTaskDelay(50);mdelay(50 );if(car->x == g_xres - CAR_LENGTH){/* 汽车到达最右边 释放信号量 *///xSemaphoreGive(xSemTicks);vTaskDelete(NULL);}}
//		}}
}

五、示例: 等待多个事件都发生

本节代码为:25_eventgroup_and,主要看nwatch\game2.c。

使用遥控器控制car1、car2。car1运行到终点后,会设置bit0事件;car2运行到终点后,会设置bit1事件;car3等待bit0、bit1的所有事件

跟24_eventgroup_or相比,只是car3的代码发生了变化。car3等待bit0、bit1事件,实验“与”的关系(倒数第2个参数),代码如下:

225     /* 等待事件:bit0 or bit1 */
226     xEventGroupWaitBits(g_xEventCar, (1<<0)|(1<<1), pdTRUE, pdTRUE, portMAX_DELAY);

实验现象:实验遥控器的1、2控制car1、car2,它们都到达终点后,car3才会启动。

相关文章:

FrereRTOS事件组

文章目录 一、事件组概念与操作1、事件组的概念2、事件组的操作 二、事件组函数1、创建2、删除3、设置事件4、等待事件5、同步点 三、示例&#xff1a;广播四、示例&#xff1a;等待一个任意事件五、示例: 等待多个事件都发生 学校组织秋游&#xff0c;组长在等待&#xff1a; …...

【经典算法】BFS_最短路问题

目录 1. 最短路问题介绍2. 算法原理和代码实现(含题目链接)1926.迷宫中离入口最近的出口433.最小基因变化127.单词接龙675.为高尔夫比赛砍树 3. 算法总结 1. 最短路问题介绍 最短路径问题是图论中的一类十分重要的问题。本篇文章只介绍边权为1(或边权相同)的最简单的最短路径问…...

【题目/训练】:双指针

引言 我们已经在这篇博客【算法/学习】双指针-CSDN博客里面讲了双指针、二分等的相关知识。 现在我们来做一些训练吧 经典例题 1. 移动零 思路&#xff1a; 使用 0 当做这个中间点&#xff0c;把不等于 0(注意题目没说不能有负数)的放到中间点的左边&#xff0c;等于 0 的…...

LLVM - 编译器后端-指令选择

一&#xff1a;概述 任何后端的核心都是指令选择。LLVM 实现了几种方法&#xff1b;在本篇文章中&#xff0c;我们将通过选择有向无环图&#xff08;DAG&#xff09;和全局指令选择来实现指令选择。 在本篇文章中&#xff0c;我们将学习以下主题&#xff1a; • 定义调…...

ES+FileBeat+Kibana日志采集搭建体验

1.环境准备 需要linux操作系统&#xff0c;并安装了docker环境 此处使用虚拟机演示。&#xff08;虚拟机和docker看参考我之前写的文章&#xff09; VirtualBox安装Oracle Linux 7.9全流程-CSDN博客 VirtualBox上的Oracle Linux虚拟机安装Docker全流程-CSDN博客 简单演示搭建ES…...

Dockerfile常用指令详解

Dockerfile 是一个用于定义 Docker 镜像构建过程的脚本文件&#xff0c;其中包含了一系列指令&#xff0c;用于指定如何构建和配置镜像。以下是一些常用的 Dockerfile 指令及其示例用法&#xff1a; 1. FROM 指定基础镜像&#xff0c;Dockerfile 必须以该指令开始。 示例&am…...

【vue】浏览器兼容相关

Vue.js 是一个流行的前端 JavaScript 框架&#xff0c;它支持构建单页应用和复杂的用户界面。Vue.js 的核心库本身对浏览器的支持情况如下&#xff1a; Vue.js 2.x 最低支持版本&#xff1a;IE9 及以上版本。特性支持&#xff1a;ES5。兼容性&#xff1a;Vue 2.x 在发布时就考…...

【区块链+金融服务】基于区块链的区域股权金融综合服务平台 | FISCO BCOS应用案例

区域性股权市场是我国资本市场的重要组成部分&#xff0c;是多层次资本市场体系的基石。区块链技术与区域性股权市场 分散特征天然匹配&#xff0c;从新型金融基础设施层面为场外参与各方提供公共的可信服务&#xff0c;以技术手段完善市场基础条 件&#xff0c;弥补区域性短板…...

string字符串和json对象相互转换问题

//响应体String responseStr EntityUtils.toString(response.getEntity());log.debug("下单响应码:{},响应体:{}",statusCode,responseStr);if(statusCode HttpStatus.OK.value()){JSONObject jsonObject JSONObject.parseObject(responseStr);if(jsonObject.cont…...

【生成式人工智能-十一一个不修改模型就能加速语言模型生成的方法】

一个加速语言模型生成的方法 现在语言模型的一个弊端speculative decoding预言家预测的问题 speculative decoding 模块的实现方法NAT Non-autoregressive模型压缩使用搜索引擎 一些更复杂些的speculative decoding 实现方式 speculative decoding 是一个适用于目前生成模型的加…...

Rust 错误处理

Rust 错误处理 Rust 是一种系统编程语言,以其内存安全、高并发和实用性而著称。在 Rust 中,错误处理是一个核心概念,它通过提供 Result 和 Option 类型来鼓励开发者显式地处理可能出现的错误,而不是依赖异常机制。本文将深入探讨 Rust 中的错误处理机制,包括 Result 和 O…...

程序与进程 linux系统

程序与进程 程序 &#xff08; program &#xff09;&#xff1a; 通常为 binary program &#xff0c;放置在储存媒体中&#xff08;如硬盘、光盘、软盘、磁带等&#xff09;&#xff0c; 为实体文件的型态存在&#xff1b;二进制文件&#xff0c;比如静态 /bin/date…...

使用MongoDB构建AI:Story Tools Studio将生成式AI引入Myth Maker AI游戏

Story Tools Studio利用先进的生成式AI技术&#xff0c;打造沉浸式、个性化、无穷尽的情景体验。 Story Tools Studio创始人兼首席执行官Roy Altman表示&#xff1a;“我们的旗舰游戏Myth Maker AI采用的是我们自主研发的、以AI为驱动的专家指导型故事生成器MUSE&#xff0c;它…...

鸿蒙UIAbility组件概述(二)

鸿蒙UIAbility组件概述 UIAbility组件基本用法指定UIAbility的启动页面获取UIAbility的上下文信息 UIAbility组件与UI的数据同步使用EventHub进行数据通信使用AppStorage/LocalStorage进行数据同步 UIAbility组件间交互&#xff08;设备内&#xff09;启动应用内的UIAbility启动…...

Oracle(70)如何优化SQL查询?

优化SQL查询是数据库管理的重要部分&#xff0c;旨在提高查询性能&#xff0c;减少响应时间和资源消耗。以下是一些常见的SQL查询优化技术&#xff0c;结合代码示例详细说明。 1. 使用索引 索引是优化查询性能的最常见方法之一。索引可以显著减少数据检索的时间。 示例 假设…...

深度剖析:Jenkins构建任务无法中断的原因及解决方案

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…...

【YOLO】常用脚本

目录 VOC转YOLO划分训练集、测试集与验证集 VOC转YOLO import os import xml.etree.ElementTree as ETdef convert(size, box):dw 1. / size[0]dh 1. / size[1]x (box[0] box[1]) / 2.0y (box[2] box[3]) / 2.0w box[1] - box[0]h box[3] - box[2]x x * dww w * dwy…...

Springboot IOC DI理解及实现+JUnit的引入+参数配置

一、JavaConfig 我们通常使用 Spring 都会使用 XML 配置&#xff0c;随着功能以及业务逻辑的日益复杂&#xff0c;应用伴随着大量的 XML 配置文件以及复杂的 bean 依赖关系&#xff0c;使用起来很不方便。 在 Spring 3.0 开始&#xff0c;Spring 官方就已经开始推荐使用 Java…...

CeresPCL 最小二乘插值(曲线拟合)

一、简介 在多项式插值时,当数据点个数较多时,插值会导致多项式曲线阶数过高,带来不稳定因素。因此我们可以通过固定幂基函数的最高次数 m(m < n),来对我们要拟合的曲线进行降阶。之前的函数形式就可以变为: 既然是最小二乘问题,那么就仍然可以使用Ceres来进行求解。 …...

【TCP/IP】自定义应用层协议,常见端口号

互联网中&#xff0c;主流的是 TCP/IP 五层协议 5G/4G 上网&#xff0c;是有自己的协议栈&#xff0c;要比 TCP/IP 更复杂&#xff08;能够把 TCP/IP 的一部分内容给包含进去了&#xff09; 应用层 可以代表我们所编写的应用程序&#xff0c;只要应用程序里面用到了网络通信…...

Frida 的下载和安装

首先要安装好 python 环境 安装 frida 和 工具包 pip install frida frida-tools 查看版本&#xff1a; frida --version 16.4.8 然后到 github 上下载对应 server &#xff08; 和frida 的版本一致 16.4.8&#xff09; Releases frida/frida (github.com) 查看手机或…...

后端开发刷题 | 链表内指定区间反转【链表篇】

描述 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转&#xff0c;要求时间复杂度 O(n)O(n)&#xff0c;空间复杂度 O(1)O(1)。 例如&#xff1a; 给出的链表为 1→2→3→4→5→NULL1→2→3→4→5→NULL, m2,n4 返回 1→4→3→2→5→NULL 数据范围&#xff1a; 链表…...

【NVMe系列-提问页与文章总结页面】

NVMe系列-提问页与文章总结页面 问题汇总NVMe协议是什么&#xff1f;PRP 与 PRP List是做什么的&#xff1f; 已写文章汇总 问题汇总 NVMe协议是什么&#xff1f; PRP 与 PRP List是做什么的&#xff1f; 已写文章汇总...

用生成器函数生成表单各字段

生成器函数生成表单字段是非常合适的用法,避免你要用纯javascript做后台时频繁的制作表单&#xff0c;而不能重复利用 //这里是javascript部分&#xff0c;formfiled.js //生成器函数对字段的处理&#xff0c;让各字段name\className\label\value\placeholder赋值到input的属性…...

【xilinx】O-RAN 无线电接口 - Vivado 2020.1 及更新工具版本的发行说明

描述 记录包含 O-RAN 无线电接口 LogiCORE IP 的发行说明和已知问题&#xff0c;包括以下内容&#xff1a; 一般信息已知和已解决的问题 解决方案 一般信息 可以在以下三个位置找到支持的设备&#xff1a; O-RAN 无线电接口 IP 产品指南&#xff08;需要访问O-RAN 安全站点&…...

结营考试- 算法进阶营地 - DAY11

结营考试 - 算法进阶营地 - DAY11 测评链接&#xff1b; A - 打卡题 考点&#xff1a;枚举&#xff1b; 分析 枚举 a _①_ b _②_ c d&#xff0c;中两个运算符的 3 3 3 种可能性&#xff0c;尝试寻找一种符合要求的答案。 参考代码 #include <bits/stdc.h> usi…...

设计模式: 访问者模式

文章目录 一、介绍二、模式结构三、优缺点1、优点2、缺点 四、应用场景 一、介绍 Visitor 模式&#xff08;访问者模式&#xff09;是一种行为设计模式&#xff0c;它允许在不修改对象结构的前提下&#xff0c;增加作用于一组对象上新的操作。就增加新的操作而言&#xff0c;V…...

selenium底层原理详解

目录 1、selenium版本的演变 1.1、Selenium 1.x&#xff08;Selenium RC时代&#xff09; 1.2、Selenium 2.x&#xff08;WebDriver整合时代&#xff09; 1.3、Selenium 3.x 2、selenium原理说明 3、源码说明 3.1、启动webdriver服务建立连接 3.2、发送操作 1、seleni…...

【Solidity】继承

继承 Solidity 中使用 is 关键字实现继承&#xff1a; contract Father {function getNumber() public pure returns (uint) {return 10;}function getNumber2() public pure virtual returns (uint) {return 20;} }contract Son is Father {}现在 Son 就可以调用 Father 的 …...

docker 安装mino服务,启动报错: Fatal glibc error: CPU does not support x86-64-v2

背景 docker 安装mino服务&#xff0c;启动报错&#xff1a; Fatal glibc error: CPU does not support x86-64-v2 原因 Docker 镜像中的 glibc 版本要求 CPU 支持 x86-64-v2 指令集&#xff0c;而你的硬件不支持。 解决办法 降低minio对应的镜像版本 经过验证&#xff1a;qu…...

地图相册系统的设计与实现

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…...

使用vh和rem实现元素响应式布局

示例代码 height: calc(100vh 30rem) vh&#xff08;Viewport Height&#xff09;&#xff1a;vh是一个相对单位&#xff0c;代表浏览器窗口高度的百分比&#xff0c;例如20vh就是浏览器窗口高度的20%。 rem&#xff08;root em&#xff09;&#xff1a;rem是通过html根元素…...

螺旋矩阵 II(LeetCode)

题目 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 解题 def generateMatrix(n):matrix [[0] * n for _ in range(n)]top, bottom 0, n - 1left, right 0, n - 1num 1while top <…...

如何快速掌握一款MCU

了解MCU特点 rom &#xff0c;ramgpiotimerpower 明确哪些资源是项目开发需要的 认真理解相关资料模块 开始编程 编写特别的验证程序&#xff08;项目不紧&#xff09;按照自己的理解编写&#xff08;老司机&#xff0c;时间紧张&#xff09; 掌握MCU基本功能 定时器 固…...

XSS-DOM

文章目录 源码SVG标签Dom-Clobbringtostring 源码 <script>const data decodeURIComponent(location.hash.substr(1));;const root document.createElement(div);root.innerHTML data;// 这里模拟了XSS过滤的过程&#xff0c;方法是移除所有属性&#xff0c;sanitize…...

uniapp去掉页面导航条

在pages.json文件中&#xff0c;globalStyle中添加 ”app-plus“:{"titleNView":false }...

MySQL数据库专栏(三)数据库服务维护操作

1、界面维护&#xff0c;打开服务窗口找到MySQL服务&#xff0c;右键单击可对服务进行启动、停止、重启等操作。 选择属性&#xff0c;还可以设置启动类型为自动、手动、禁用。 2、指令维护 卸载服务&#xff1a;sc delete [服务名称] 例如&#xff1a;sc delete MySQL 启动服…...

【QT】基于UDP/TCP/串口 的Ymodom通讯协议客户端

【QT】基于UDP/TCP/串口的Ymodom通讯协议客户端 前言Ymodom实现QT实现开源库的二次开发-1开源库的二次开发-2 串口方式实现TCP方式实现UDP方式实现补充&#xff1a;文件读取补充&#xff1a;QT 封装成EXE 前言 Qt 运行环境 Desktop_Qt_5_11_2_MSVC2015_64bit &#xff0c;基于…...

超详细!!!electron-vite-vue开发桌面应用之引入UI组件库element-plus(四)

云风网 云风笔记 云风知识库 一、安装element-plus以及图标库依赖 npm install element-plus --save npm install element-plus/icons-vue npm i -D unplugin-icons二、vite按需引入插件 npm install -D unplugin-vue-components unplugin-auto-importunplugin-vue-componen…...

【排序篇】实现快速排序的三种方法

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 文章目录 1 交换排序1.1 冒泡排序1.2 快速排序1.2.1 hoare版本1.2.2 挖坑法1.2.3 前后指针…...

Java 标识符(详解)

文章目录 一、简介二、命名规则三、命名规范 一、简介 在 Java 中&#xff0c;用于给变量、类、方法等命名的符号组合&#xff0c;我们称之为Java标识符&#xff0c;它就像是给这些编程元素贴上的独特标签&#xff0c;以便在程序中能够准确地引用和操作它们。 二、命名规则 标…...

2024年,有哪些优质的计算机书籍推荐?

在2024年&#xff0c;计算机领域的新书层出不穷&#xff0c;涵盖了从基础理论到前沿技术的多个方面。以下是今年出版的几本备受关注的计算机新书。 1. AI与机器学习类 1、深度学习详解 1.李宏毅老师亲笔推荐&#xff0c;杨小康、周明、叶杰平、邱锡鹏鼎力推荐! 2.数百万次播…...

Python基础知识点--总结

1. 注释 注释用于提高代码的可读性&#xff0c;在代码中添加说明文字&#xff0c;使代码更容易理解。 单行注释&#xff1a;使用 # 符号开头&#xff0c;注释内容在符号之后的行内。多行注释&#xff1a;使用三引号&#xff08; 或 """&#xff09;包裹注释内…...

高效记录与笔记整理的策略:工具选择、结构设计与复习方法

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…...

Request重复读的问题

换了新工作都有时间写文章&#xff0c;每天也是加班到很晚&#xff0c;也不是工作内容多&#xff0c;主要是还是效率低&#xff0c;要考虑多干的很心累。 一、关于request重复读的问题&#xff0c;从源码的角度来分析 为什么他不能重复读 跳转 再看源码前可能需要一些基础的…...

Linux学习第60天:Linux驱动开发的一些总结

今天是Linux驱动开发的最后一个章节&#xff0c;题目中标明是60天完成的&#xff0c;其实在实际学习及笔记的整理中不止是60天。中间有过断更&#xff0c;有时断更的时间还是挺长的。这是在整个Linux驱动开发学习中最不满意的地方。 题目为Linux学习&#xff0c;其实这个题目有…...

OPP || 继承和抽象类 || 访问控制

OPP面向对象程序设计 数据抽象&#xff1a;类的接口声明和定义实现分离继承&#xff1a;类构成的&#xff08;树型&#xff09;层次关系动态绑定&#xff1a;忽略相似类型区别&#xff0c;用统一的方式使用 基类派生类&#xff1a; 继承&#xff1a;类名 冒号 访问说明符 …...

蓝牙音视频远程控制协议(AVRCP) command跟response介绍

零.声明 本专栏文章我们会以连载的方式持续更新&#xff0c;本专栏计划更新内容如下&#xff1a; 第一篇:蓝牙综合介绍 &#xff0c;主要介绍蓝牙的一些概念&#xff0c;产生背景&#xff0c;发展轨迹&#xff0c;市面蓝牙介绍&#xff0c;以及蓝牙开发板介绍。 第二篇:Trans…...

MySQL的InnoDB存储引擎中的Buffer Pool机制

目录 Buffer Pool 简介 定义 为什么需要Buffer Pool 图解重点知识 Buffer Pool 的组成 数据页&#xff08;Data Pages&#xff09; 索引页&#xff08;Index Pages&#xff09; 插入缓冲页&#xff08;Insert Buffer Pages&#xff09; undo页&#xff08;Undo Pages&a…...

5. MongoDB 文档插入、更新、删除、查询

1. 插入文档 文档的数据结构和JSON基本一样。所有存储在集合中的数据都是BSON格式。 BSON是一种类似JSON的二进制形式的存储格式&#xff0c;是Binary JSON的简称。常用的插入文档方法包括&#xff1a; db.collection.insertOne()&#xff1a;插入单个文档db.collection.inse…...