FreeRTOS_信号量之互斥信号量

目录

1. 互斥信号量

1.1 互斥信号量简介

1.2 创建互斥信号量

1.2.1 函数 xSemaphoreCreateMutex()

1.2.2 函数 xSemaphoreCreateMutexStatic()

1.2.3 互斥信号量创建过程分析

1.2.4 释放互斥信号量

1.2.5 获取互斥信号量

2. 互斥信号量操作实验

2.1 实验程序

2.1.1 main.c

2.1.2 实验现象


1. 互斥信号量

1.1 互斥信号量简介

        互斥信号量其实就是一个拥有优先级继承的二值信号量,在同步的应用中(任务与任务或中断与任务之间的同步)二值信号量最适合。互斥信号量适合用于那些需要互斥访问的应用中。在互斥访问中互斥信号量相当于一把钥匙,当任务想要使用资源的时候就必须先获得这个钥匙,当使用完资源以后就必须归还这个钥匙,这样其他的任务就可以拿着这个钥匙去使用资源。

        互斥信号量使用和二值信号量相同的 API 操作函数,所以互斥信号量也可以设置阻塞时间,不同于二值信号量的是互斥信号量具有优先级继承的特性。当一个互斥信号量正在被一个低优先级的任务使用,而此时有个高优先级的任务也尝试获取这个互斥信号量的话就会被阻塞。这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级,这个过程就是优先级继承。优先级继承尽可能的降低了高优先级任务处于阻塞态的时间,并且将已经出现的 “优先级翻转” 的影响降到最低。

优先级继承尽可能的降低了高优先级任务处于阻塞态的时间,并且将已经出现的 “优先级翻转” 的影响降到最低。
       
意思就是说:低优先级的任务获得互斥信号量,此时高优先级的任务无法访问获得互斥信号量,其他中等优先级的任务也无法获得互斥信号量,这样一来,低优先级任务就不能被中等优先级任务所打断,高优先级任务只需要等待低优先级任务释放互斥信号量即可,不用担心被其他的中等任务所打断;这也就是为什么降低高优先级任务处于阻塞态的时间,降低了优先级翻转的可能性!

        优先级继承并不能完全的消除优先级翻转,它只是尽可能的降低优先级翻转带来的影响。硬实时应用应该在设计之初就要避免优先级翻转的发生。

互斥信号量不能用于中断服务函数中:

        互斥信号量具有优先级继承的机制,只能用在任务中,不能用于中断服务函数。

        中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

1.2 创建互斥信号量

        FreeRTOS提供两个互斥信号量创建函数。

函数:

        xSemaphoreCreateMutex()                使用动态方法创建互斥信号量

        xSemaphoreCreateMutexStatic()        使用静态方法创建互斥信号量

1.2.1 函数 xSemaphoreCreateMutex()

        此函数用于创建一个互斥信号量,所需要的内存通过动态内存管理方法分配。此函数本质是一个宏,真正完成信号量创建的是函数 xQueueCreateMutex(),此函数原型如下:

SemaphoreHandle_t xSemaphoreCreateMutex(void)

参数:

        无。

返回值:

        NULL:互斥信号量创建失败。

        其他值:创建成功的互斥信号量的句柄。

1.2.2 函数 xSemaphoreCreateMutexStatic()

        此函数也是创建互斥信号量的,只不过使用此函数创建互斥信号量的话信号量所需要的 RAM 需要由用户来分配,此函数是一个宏,具体创建过程是通过函数 xQueueCreateMutexStatic() 来完成的,函数原型如下:

SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t *pxMutexBuffer)

参数:

        pxMutexBuffer:此参数指向一个 StaticSemaphore_t 类型的变量,用来保存信号量结构体。

返回值:

        NULL:互斥信号量创建失败。

        其他值:创建成功的互斥信号量的句柄。

1.2.3 互斥信号量创建过程分析

        这里只分析动态创建互斥信号量函数 xSemaphoreCreateMutex(),此函数是个宏,定义如下:

#define  xSemaphoreCreateMutex()  xQueueCreateMutex(queueQUEUE_TYPE_MUTEX)

        可以看出,真正干事的是函数 xQueueCreateMutex(),此函数在文件 queue.c 中有如下定义,

QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) 
{ Queue_t *pxNewQueue; const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize,     (1) ucQueueType ); prvInitialiseMutex( pxNewQueue );                                               (2) return pxNewQueue; 
}

(1)、调用函数 xQueueGenericCreate() 创建一个队列,队列长度为 1 ,队列项长度为 0 ,队列类型为参数 ucQueueType。由于本函数创建的是互斥信号量,所以参数 ucQueueType 为 queueQUEUE_TYPE_MUTEX。

(2)、调用函数 prvInitialiseMutex() 初始化互斥信号量。

函数 prvInitialiseMutex() 初始化互斥信号量代码如下:

static void prvInitialiseMutex( Queue_t *pxNewQueue ) 
{ if( pxNewQueue != NULL ) { //虽然创建队列的时候会初始化队列结构体的成员变量,但是此时创建的是互斥 //信号量,因此有些成员变量需要重新赋值,尤其是那些用于优先级继承的。 pxNewQueue->pxMutexHolder = NULL;                                 (1) pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;                     (2) //如果是递归互斥信号量的话。 pxNewQueue->u.uxRecursiveCallCount = 0;                             (3) traceCREATE_MUTEX( pxNewQueue ); //释放互斥信号量 ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U,queueSEND_TO_BACK ); } else { traceCREATE_MUTEX_FAILED(); } 
} 

(1)和(2)、队列结构体中 Queue_t 中没有 pxMutexHolder 和 uxQueueType 这两个成员变量,这两个成员变量其实是一个宏,专门为互斥信号量准备的,在文件 queue.c 中有如下定义:

#define pxMutexHolder    pcTail
#define uxQueueType      pcHead
#define queueQUEUE_IS_MUTEX    NULL

        当 Queue_t 用于表示队列的时候 pcHead 和 pcTail 指向队列的存储区域,当 Queue_t 用于表示互斥信号量的时候就不需要 pcHead 和 pcTail 了。当用于互斥信号量的时候将 pcHead 指向 NULL 来表示 pcTail 保存着互斥队列的所有者,pxMutexHolder 指向拥有互斥信号量的那个任务的任务控制块。重命名 pcTail 和 pcHead 是为了增强代码的可读性。

(3)、如果创建的信号量是递归互斥信号量的话,还需要初始化队列结构体中的成员变量 u.uxRecursiveCallCount。

        互斥信号量创建成功以后会调用函数 xQueueGenericSend() 释放一次信号量,说明互斥信号量默认就是有效的!

1.2.4 释放互斥信号量

        释放互斥信号量的时候和二值信号量、计数型信号量一样,都是用的函数 xSemaphoreGive()(实际上完成信号量释放的是函数 xQueueGenericSend())。由于互斥信号量涉及到优先级继承的问题,所以具体的处理过程会有区别。使用函数 xSemaphoreGive() 释放信号量最重要的一步就是将 uxMessageWaiting 加一,而这一步就是通过函数 prvCopyDataToQueue() 来完成的,释放信号量的函数 xQueueGenericSend() 会调用 prvCopyDataToQueue()。互斥信号量的优先级继承也是在函数 prvCopyDataToQueue() 中完成的,此函数有如下一段代码:

static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void * pvItemToQueue, const BaseType_t xPosition ) 
{ BaseType_t xReturn = pdFALSE; UBaseType_t uxMessagesWaiting; uxMessagesWaiting = pxQueue->uxMessagesWaiting; if( pxQueue->uxItemSize == ( UBaseType_t ) 0 ) { #if ( configUSE_MUTEXES == 1 ) //互斥信号量 { if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )             (1) { xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder );                        (2) pxQueue->pxMutexHolder = NULL;                            (3) } else { mtCOVERAGE_TEST_MARKER(); } } #endif /* configUSE_MUTEXES */ } /*********************************************************************/ /*************************省略掉其他处理代码**************************/ /*********************************************************************/ pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; return xReturn; 
} 

(1)、当前操作的是互斥信号量。

(2)、调用函数 xTaskPriorityDisinherit() 处理互斥信号量的优先级继承问题。

(3)、互斥信号量释放以后,互斥信号量就不属于任何任务了,所以 pxMutexHolder 要指向 NULL。

函数 xTaskPriorityDisinherit() 代码如下:

BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) 
{ TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; BaseType_t xReturn = pdFALSE; if( pxMutexHolder != NULL )                                         (1) { //当一个任务获取到互斥信号量以后就会涉及到优先级继承的问题,正在释放互斥 //信号量的任务肯定是当前正在运行的任务 pxCurrentTCB。 configASSERT( pxTCB == pxCurrentTCB ); configASSERT( pxTCB->uxMutexesHeld ); ( pxTCB->uxMutexesHeld )--;                                     (2) //是否存在优先级继承?如果存在的话任务当前优先级肯定和任务基优先级不同。if( pxTCB->uxPriority != pxTCB->uxBasePriority )                 (3) { //当前任务只获取到了一个互斥信号量 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 )                 (4) { if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )         (5) { taskRESET_READY_PRIORITY( pxTCB->uxPriority );         (6) } else { mtCOVERAGE_TEST_MARKER(); } //使用新的优先级将任务重新添加到就绪列表中 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); pxTCB->uxPriority = pxTCB->uxBasePriority; (7) /* Reset the event list item value. It cannot be in use for any other purpose if this task is running, and it must be running to give back the mutex. */ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), \             (8) ( TickType_t ) configMAX_PRIORITIES - \ ( TickType_t ) pxTCB->uxPriority ); prvAddTaskToReadyList( pxTCB );                                 (9) xReturn = pdTRUE;                                                 (10) } else { mtCOVERAGE_TEST_MARKER(); } } else { mtCOVERAGE_TEST_MARKER(); } } else { mtCOVERAGE_TEST_MARKER(); } return xReturn; 
}

(1)、函数的参数 pxMutexHolder 表示拥有此互斥信号量任务控制块,所以要先判断此互斥信号量是否已经被其他任务获取。

(2)、有的任务可能会获取多个互斥信号量,所以就需要标记任务当前获取到的互斥信号量个数,任务控制块结构体成员变量 uxMutexesHeld 用来保存当前任务获取到的互斥信号量个数。任务每释放一次互斥信号量,变量 uxMutexesHeld 肯定就要减一。

(3)、判断是否存在优先级继承,如果存在的话任务的当前优先级肯定不等于任务的基优先级(任务的基优先级是指任务在创建时分配的固定优先级。它是一个用于调度任务的数值,数值越高,优先级越高)

(4)、判断当前释放的是不是任务所获取到的最后一个互斥信号量,因为如果任务还获取了其他互斥信号量的话就不能处理优先级继承。优先级继承的处理必须是在释放最后一个互斥信号量的时候。

(5)、优先级继承的处理说白了就是把任务的当前优先级降低到任务的基优先级,所以要把当前任务先从任务就绪表中移除。当任务优先级恢复为原来的优先级以后再重新加入到就绪表中。

FreeRTOS 是一种实时操作系统 (RTOS),用于嵌入式系统的开发。优先级继承是一种调度策略,用于解决优先级翻转问题。

在多任务系统中,任务可以具有不同的优先级,优先级较高的任务可以抢占优先级较低的任务。然而,当存在任务依赖关系时,可能会出现优先级反转问题。

优先级翻转问题是当一个具有较低优先级的任务占用一个共享资源时,一个具有较高优先级的任务因为等待该资源而被阻塞。此时,更高优先级任务无法运行,从而导致系统的响应性能下降。

通过优先级继承,当一个高优先级任务需要使用一个低优先级任务占用的资源时,低优先级任务的优先级会临时提升至与高优先级任务相同的优先级,以确保高优先级任务能够尽快获得所需资源,当高优先级任务释放该资源后,低优先级任务的优先级恢复原状。

(6)、如果任务继承来的这个优先级对应的就绪表中没有其他任务的话就将取消这个优先级的就绪态。

(7)、重新设置任务的优先级为任务的基优先级 uxBasePriority。

(8)、复位任务的事件列表项。

(9)、将优先级恢复后的任务重新添加到任务就绪表中。

(10)、返回 pdTRUE,表示需要进行任务调度。

1.2.5 获取互斥信号量

        获取互斥信号量的函数同获取二值信号量和计数型信号量的函数相同,都是 xSemaphoreTake()(实际执行信号量获取的函数是 xQueueGenericReceive()),获取互斥信号量的过程也需要处理优先级继承的问题,函数 xQueueGenericReceive()在文件 queue.c 中有定义)

2. 互斥信号量操作实验

本实验设计了四个任务:start_task、high_task、middle_task、low_task,这四个任务的任务功能如下:

        start_task:用来创建其他的三个任务。

        high_task:高优先级任务,会获取互斥信号量,获取成功以后会进行相应的处理,处理完成以后就会释放互斥信号量。

        middle_task:中等优先级任务,一个简单的应用任务。

        low_task:低优先级任务,和高优先级任务一样,会获取互斥信号量,获取成功以后会进行相应的处理,不过不同之处在于低优先级的任务占用互斥信号量的时间要久一点(软件模拟占用)。

        实验中创建了一个互斥信号量 MutexSemaphore,高优先级和低优先级这两个任务会使用这个互斥信号量。

2.1 实验程序

2.1.1 main.c

#include "stm32f4xx.h"  
#include "FreeRTOS.h" //这里注意必须先引用FreeRTOS的头文件,然后再引用task.h
#include "task.h"     //存在一个先后的关系
#include "LED.h"
#include "LCD.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"
#include "string.h"
#include "beep.h"
#include "malloc.h"
#include "timer.h"
#include "queue.h"
#include "semphr.h"//任务优先级
#define START_TASK_PRIO     1       //用于创建其他三个任务
//任务堆栈大小
#define START_STK_SIZE      256
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);//任务优先级
#define LOW_TASK_PRIO     2       //低优先级任务,会获取互斥信号量,获取成功以后进行相应的处理,占用互斥信号量的时间要久一点
//任务堆栈大小 
#define LOW_STK_SIZE      256
//任务句柄
TaskHandle_t LowTask_Handler;
//任务函数
void low_task(void *pvParameters);//任务优先级
#define MIDDLE_TASK_PRIO     3       //中等优先级任务,一个简单的应用任务
//任务堆栈大小
#define MIDDLE_STK_SIZE      256
//任务句柄
TaskHandle_t MiddleTask_Handler;
//任务函数
void middle_task(void *pvParameters);//任务优先级
#define HIGH_TASK_PRIO     4       //高优先级任务,会获取互斥信号量,获取成功以后会进行相应的处理,处理完成以后会释放互斥信号量
//任务堆栈大小
#define HIGH_STK_SIZE      256
//任务句柄
TaskHandle_t HighTask_Handler;
//任务函数
void high_task(void *pvParameters);//互斥信号量句柄
SemaphoreHandle_t MutexSemaphore;   //互斥信号量//LCD刷屏时使用的颜色
int lcd_discolor[14]={	WHITE, BLACK, BLUE,  BRED,      GRED,  GBLUE, RED,   MAGENTA,       	 GREEN, CYAN,  YELLOW,BROWN, 			BRRED, GRAY };int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);  delay_init(168);uart_init(115200);LED_Init();KEY_Init();BEEP_Init();LCD_Init();my_mem_init(SRAMIN);        //初始化内部内存池POINT_COLOR=RED;LCD_ShowString(30,10,200,16,16,"ATK STM32F407");LCD_ShowString(30,30,200,16,16,"FreeRTOS Example");LCD_ShowString(30,50,200,16,16,"Mutex Semaphore");LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");LCD_ShowString(30,90,200,16,16,"2023/10/31");//创建开始任务xTaskCreate((TaskFunction_t)start_task,         //任务函数(const char*   )"start_task",       //任务名称(uint16_t      )START_STK_SIZE,     //任务堆栈大小(void*         )NULL,               //传递给任务函数的参数(UBaseType_t   )START_TASK_PRIO,    //任务优先级(TaskHandle_t* )&StartTask_Handler);//任务句柄vTaskStartScheduler();          //开启任务调度
}//开始任务任务函数
void start_task(void *pvParameters)
{taskENTER_CRITICAL();       //进入临界区//创建互斥信号量MutexSemaphore=xSemaphoreCreateMutex();  //创建互斥信号量函数,返回创建成功的互斥信号量句柄//创建高优先级任务xTaskCreate((TaskFunction_t)high_task,         //任务函数(const char*   )"high_task",       //任务名称(uint16_t      )HIGH_STK_SIZE,     //任务堆栈大小(void*         )NULL,               //传递给任务函数的参数(UBaseType_t   )HIGH_TASK_PRIO,    //任务优先级(TaskHandle_t* )&HighTask_Handler);//任务句柄//创建中等优先级任务xTaskCreate((TaskFunction_t)middle_task,         //任务函数(const char*   )"middle_task",       //任务名称(uint16_t      )MIDDLE_STK_SIZE,     //任务堆栈大小(void*         )NULL,               //传递给任务函数的参数(UBaseType_t   )MIDDLE_TASK_PRIO,    //任务优先级(TaskHandle_t* )&MiddleTask_Handler);//任务句柄//创建低优先级任务xTaskCreate((TaskFunction_t)low_task,         //任务函数(const char*   )"low_task",       //任务名称(uint16_t      )LOW_STK_SIZE,     //任务堆栈大小(void*         )NULL,               //传递给任务函数的参数(UBaseType_t   )LOW_TASK_PRIO,    //任务优先级(TaskHandle_t* )&LowTask_Handler);//任务句柄vTaskDelete(StartTask_Handler);taskEXIT_CRITICAL();            //退出临界区
}//高优先级任务任务函数
void high_task(void *pvParameters)
{u8 num;POINT_COLOR=BLACK;LCD_DrawRectangle(5,110,115,314);   //画一个矩形LCD_DrawLine(5,130,115,130);        //画线POINT_COLOR=BLUE;LCD_ShowString(6,111,110,16,16,"High Task");while(1){vTaskDelay(500);   //延时500ms,也就是500个时钟节拍num++;printf("high task Pend Semaphore\r\n");xSemaphoreTake(MutexSemaphore,portMAX_DELAY);    //获取互斥信号量//获取互斥信号量的阻塞时间设置为无限等待,既然这个任务可以获取互斥信号量,那么总有一个时刻可以获取到互斥信号量//否则程序就会卡在这里printf("high task Running!\r\n");   //获取到互斥信号量,高优先级任务开始运行LCD_Fill(6,131,114,313,lcd_discolor[num%14]);   //填充区域LED1=!LED1;xSemaphoreGive(MutexSemaphore);           //释放互斥信号量,当高优先级任务获取互斥信号量完成相应的处理之后,就会释放掉信号量vTaskDelay(500);                //延时500ms,也就是500个时钟节拍}
}//中等优先级任务的任务函数
void middle_task(void *pvParameters)
{u8 num;POINT_COLOR=BLACK;LCD_DrawRectangle(125,110,234,314);     //画一个矩形LCD_DrawLine(125,130,234,130);      //画线POINT_COLOR=BLUE;LCD_ShowString(126,111,110,16,16,"Middle Task");while(1){num++;printf("middle task Running!\r\n");LCD_Fill(126,131,233,313,lcd_discolor[13-num%14]);  //倒过来填充区域LED0=!LED0;vTaskDelay(1000);       //延时1s,也就是1000个时钟节拍}
}//低优先级任务的任务函数
//低优先级任务占用互斥信号量的时间更长
void low_task(void *pvParameters)
{static u32 times;while(1){xSemaphoreTake(MutexSemaphore,portMAX_DELAY);  //获取二值信号量printf("low task Running!\r\n");            for(times=0;times<20000000;times++)         //模拟低优先级占用二值信号量{taskYIELD();            //发起任务调度//这也就保证了低优先级任务占用二值信号量的时间更长//因为我一旦发起了任务调度,低优先级抢占的这个二值信号量是不能被高优先级的任务所抢占的}xSemaphoreGive(MutexSemaphore);           //释放二值信号量vTaskDelay(1000);       //延时1s,也就是1000个时钟节拍}
}

2.1.2 实验现象

通过上述串口输出的数据进行分析!

        首先高优先级任务存在延时,所以中等优先级任务抢占 CPU,中等优先级任务运行一个时间片之后,低优先级任务获取互斥信号量,高优先级任务延时时间到以后抢占CPU使用权,高优先级任务请求信号量,等待低优先级任务释放互斥信号量,此时中等优先级任务不会运行,因为互斥信号量优先级继承的缘故,低优先级任务临时获得和高优先级任务同等的优先级,等待低优先级任务释放互斥信号量之后,高优先级任务得以运行,高优先级任务释放信号量之后,任务调度,中等优先级任务运行,高优先级任务请求信号量,此时信号量被高优先级任务获取,高优先级任务运行,然后中等任务运行,低优先级任务运行!!!

互斥信号量的精髓在于:低优先级任务正在使用互斥信号量,而高优先级任务请求使用互斥信号量,此时会临时的将低优先级任务的优先级提高到和高优先级任务一个层次,这时被提升上来的任务就不会被其他优先级任务所打断,最大程度保证高优先级任务尽快获得互斥信号量,提高系统的响应性能。当高优先级任务释放信号量之后,被提升的任务回到之前的优先级。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux:文件操作

目录 一、关于文件 1、文件类的系统接口 2、文件的含义 二、文件操作 1、C语言文件相关接口 2、系统接口 open close write read 三、文件描述符 关于fd fd的分配规则 输出重定向示例 输入重定向示例 追加重定向示例 dup2函数 缓冲区 stdout与stderr perror…

Webpack常见的插件和模式

文章目录 一、认识插件Plugin1.认识Plugin 二、CleanWebpackPlugin三、HtmlWebpackPlugin1.生成index.html分析2.自定义HTML模板3.自定义模板数据填充 四、DefinePlugin1.DefinePlugin的介绍2.DefinePlugin的使用 五、Mode配置 一、认识插件Plugin 1.认识Plugin Webpack的另一…

数据结构:算法(特性,时间复杂度,空间复杂度)

目录 1.算法的概念2.算法的特性1.有穷性2.确定性3.可行性4.输入5.输出 3.好算法的特质1.正确性2.可读性3.健壮性4.高效率与低存储需求 4.算法的时间复杂度1.事后统计的问题2.复杂度表示的计算1.加法规则2.乘法规则3.常见函数数量级比较 5.算法的空间复杂度1.程序的内存需求2.例…

5.3 用户定义的完整性

思维导图&#xff1a; 5.3 用户定义的完整性 用户定义的完整性是确保数据库中的数据满足特定应用的语义要求。这是通过关系数据库管理系统(RDBMS)中的内置机制来完成的&#xff0c;不需要依赖应用程序来执行。 5.3.1 属性上的约束条件 1. 定义属性上的约束条件 当在CREATE T…

centos7安装oxidized备份软件

首先需要提前下载ruby&#xff0c;因为默认yum安装的版本太低 https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.0.tar.gz 1、yum remove ruby ruby-devel&#xff08;有就卸载&#xff0c;没有则忽略&#xff09; 2、将下载好的ruby包解压到/opt下 [rootoxidized ruby-…

Python---字符串输入和输出---input()、格式化输出:%,f形式,format形式

字符串输入: 在Python代码中&#xff0c;我们可以使用input()方法来接收用户的输入信息。记住&#xff1a;在Python中&#xff0c;input()方法返回的结果是一个字符串类型的数据。 如果之后使用输入的数据&#xff0c;一定要记得利用数据类型转换。 相关链接&#xff1a;Pyt…

nodejs升级或降级

node有一个模块叫n&#xff0c;是专门用来管理node.js的版本。 升级或降级步骤 1 、安装n模块 npm install -g n 2、 升级node.js到最新稳定版 n stable Ps: n后面也可以跟随版本号&#xff08;用于升级或降级&#xff09;比如&#xff1a; n v16.12.0

蚂蚁SOFA Stack融合大模型发布升级版 将为机构产研效能提升30%

11月1日&#xff0c;在云栖大会上&#xff0c;蚂蚁集团正式发布CodeFuse全面加持的SOFAStack5.0升级版本&#xff0c;向企业提供全方位研发运维智能助手相关能力。这是继蚂蚁集团在外滩大会发布代码大模型CodeFuse之后&#xff0c;首次公布面向行业的商业化产品进展。 “大模型…

Controllable Guide-Space for Generalizable Face Forgery Detection

一、研究背景 以往工作专注于提取伪造特征的共同特性和真假域鉴别性信息&#xff0c;以提升特征泛化性。 但在训练过程中&#xff0c;这些方法只区分真假域&#xff0c;并将不同的伪造域看作一类而不加以区分。 这会导致伪造样本进一步以伪造不相关特征&#xff08;如&#xff…

ACID模型

ACID 是数据库管理系统&#xff08;DBMS&#xff09;中用来确保事务处理正确性和可靠性的四个特性的首字母缩写。ACID 是指原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;和持久性&#xff08…

如何通过 NAT 模式连接VMware虚拟机以及存在和不存在ens33文件的解决方案

文章目录 前言1 VMware配置1.1 打开vmvare虚拟网络编辑器1.2 取消使用本地DHCP1.3 NAT设置 2 虚拟机的配置2.1 存在ens332.2.1 修改ifcfg-ens33文件2.2.1.1 为什么设置BOOTPROTOstatic&#xff1f;2.2.1.2 如何选择使用static还是dhcp&#xff1f; 2.2.2 关闭防火墙 2.2 不存在…

VScode clangd 插件浏览 linux 源码

文章目录 VScode clangd 插件浏览 linux 源码clangd 安装与配置VScode 插件安装clangd 安装方法一方法二 clangd 配置 cmake 生成bear 生成 compile_commands.json触发 clangd linux 内核脚本生成 compile_commands.json 文件三种方式对比 VScode clangd 插件浏览 linux 源码 …

抖音协议算法最新版

抖音的协议算法是指用于推荐内容和个性化用户体验的算法系统。这些算法根据用户的兴趣、行为和偏好来推荐适合他们的视频内容&#xff0c;以提供更好的用户体验。 抖音的协议算法使用了大量的数据和机器学习技术来实现个性化推荐。以下是一些可能应用于抖音协议算法的技术和方法…

使用Objective-C和ASIHTTPRequest库进行Douban电影分析

概述 Douban是一个提供图书、音乐、电影等文化内容的社交网站&#xff0c;它的电影频道包含了大量的电影信息和用户评价。本文将介绍如何使用Objective-C语言和ASIHTTPRequest库进行Douban电影分析&#xff0c;包括如何获取电影数据、如何解析JSON格式的数据、如何使用代理IP技…

机器学习-特征工程

一、特征工程介绍 1.1 什么是特征 数值特征&#xff08;连续特征&#xff09;、文本特征&#xff08;离散特征&#xff09; 1.2 特征的种类 1.3 特征工程 特征是机器学习可疑直接使用的&#xff0c;模型和特征之间是一个循环过程&#xff1b; 实际上特征工程就是将原始数据…

3 Tensorflow构建模型详解

上一篇&#xff1a;2 用TensorFlow构建一个简单的神经网络-CSDN博客 本篇目标是介绍如何构建一个简单的线性回归模型&#xff0c;要点如下&#xff1a; 了解神经网络原理构建模型的一般步骤模型重要参数介绍 1、神经网络概念 接上一篇&#xff0c;用tensorflow写了一个猜测西…

微信小程序:自定义组件传值——获取手机验证码

一&#xff1a;遇到的问题 通过自己自定义的组件编写的表单&#xff0c;发现传值不了&#xff0c;点击后收到的值为空。 二&#xff1a;创建组件 先在根目录创建components文件夹&#xff0c;创建img-verify文件夹&#xff08;这个是我取的组件名字&#xff09;&#xff0c;在…

什么是 DevOps

DevOps是一套融合软件开发&#xff08;Dev&#xff09;和 IT 运营&#xff08;Ops&#xff09;的实践&#xff0c;旨在缩短应用程序开发周期并确保以高软件质量持续交付&#xff0c;通过采用 DevOps 实践&#xff0c;您可以帮助组织更可靠、更快速、更高效地交付软件。 什么是…

一百九十八、Java——IDEA项目中有参构造、无参构造等快捷键(持续梳理中)

一、目的 由于IDEA项目中有很多快捷键&#xff0c;可以很好的提高开发效率&#xff0c;因此整理一下 二、快捷键 &#xff08;一&#xff09;快捷键生成public static void main(String[] args) {} 快捷键&#xff1a;psvm &#xff08;二&#xff09;快捷键在test中创建cn…

MacOS安装git

文章目录 通过Xcode Command Lines Tool安装(推荐)终端直接运行git命令根据流程安装先安装Command Lines Tool后再安装git 官网下载二进制文件进行安装官方国外源下载二进制文件(不推荐)国内镜像下载二进制文件(推荐)安装git 通过Xcode Command Lines Tool安装(推荐) 简单来讲C…