FreeRTOS-任务通知详解

news2024/9/21 22:56:36

✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!!
📃个人主页:@rivencode的个人主页
🔥系列专栏:玩转FreeRTOS
💬保持学习、保持热爱、认真分享、一起进步!!!

目录

  • 前言
  • 一、任务通知的简介
  • 二、任务通知源码分析
    • 1.发送通知函数xTaskGenericNotify
    • 2.接收任务通知 ulTaskNotifyTake()
    • 3.接收任务通知函数xTaskNotifyWait()
  • 三.总结

前言

FreeRTOS越学越简单,前面已经把真实的队列、信号量、事件组全部学完,现在学个任务通知去模拟这些东西,真的都学会了,模拟的还不会嘛,所以我们的本文的重点主要有两点:1.搞明白任务通知的三个状态(实现任务通知的关键),2.明白任务通知的优缺点,以及任务通知模拟出来的队列、信号量、事件组与真实的有何区别。

一、任务通知的简介

说是任务通知,倒不如说通知任务,所谓任务通知核心就是一个32位的无符号整数和一个8位的通知状态,而这两玩意就在任务控制块中,则所谓通知任务就是一个任务或者中断改写另外一个任务中的32位的无符号整数,只不过改写这个整数的方式可以有所不同(1.可以让这个整数加1: 模拟信号量 2. 设置该整数的指定的某些位:模拟事件组 3.直接选择覆盖或者不覆盖写入: 模拟消息队列)。

  • 1.任务的通知状态:任务通知有三种状态

未等待通知状态:就是任务的初始状态

等待通知状态:当任务在没有通知的时候接收通知时(也就是任务没有接收到通知的时候调用了接收通知的函数,则此时必定接收不到通知,把该任务标记为等待通知状态(去等别的任务发给我通知),任务进入阻塞态),这样做的用处是什么呢? 答:当另外一个任务发通知给该任务时,此时发现任务处于等待通知的状态,然后就可以即可把该任务唤醒。

等待接收通知状态:当有其他任务向任务发送通知,但任务还未接收这一通知的这段期间内(当其他任务给该任务发了通知,但是该任务还没有接收,则将该任务标记为等待接收通知状态),这样做的用处就是当该任务调用了接收通知的函数,发现自身的状态为等待接收通知状态,则不用进入阻塞,直接接收通知值。

为什么要搞一个这样的通知状态?
答:
1.为了判断任务是否接收到了通知
2.不需要一个链表来挂载因等不到通知而阻塞任务,可以直接将任务挂入阻塞链表,因为当调用发送通知函数去唤醒该任务时只需要判断它是否处于等待通知状态(因等待通知进入阻塞)。
像队列它有一个当前消息个数的变量可以知道队列中是否有消息,像信号量0就是没消息

那为什么任务通知不能以通知值是否为0判断是否有消息呢?
确实模拟信号量确实是怎么做的,但是如果是模拟队列的话,就不能怎么搞了,因为我发送一个0,0也算是数据,所以需要一个

如果现在还搞不懂这三个状态什么意思,没关系看后面的源码就懂了。

  • 2.任务通知的优缺点:

(1).任务通知的优点
按照FreeRTOS官方的说法使用任务通知比通过队列、事件标志组或信号量通信方式解除阻塞的任务要快 45%,并且更加省 RAM 内存空间,因为像队列、信号量、事件组这些通信方式使用前必须先创建,拿队列来说如下图所示,申请内存的时候至少需要下图这么多变量,而任务通知是任务结构体中自带的一个32位的无符号整数,一个8位的通知状态变量,一共就5个字节。
在这里插入图片描述
使用任务通知不需要创建,因为当创建任务的时候就已经默认创建了这两个变量,任务控制块中的两个变量如下图所示,当然这里是一个数组(为了方便以后扩展),但是数组的元素个数默认为1。
在这里插入图片描述
(2).任务通知的缺点
虽然说任务通知可以模拟这么多通信方式,但是肯定有限制、有缺点,不然还要这些队列、信号量、事件组干嘛。
1.不能发送通知到中断
原因很简单,任务通知、任务通知,人家通知的是任务,是修改任务控制块中那个32位无符号整数的值,中断并没有任务控制块这一说,但为什么队列、信号量、事件组这些就可以呢,说到底人家创建了一个独立的队列、信号量、事件组结构体当然谁都可以访问里面的内容,但是可以在中断中发送通知给其他任务,这个是没毛病的。
2.不能发送通知给多个任务
任务通知只能指定发送给某一个任务而不能广播,而队列、信号量、事件组任何中断和任务都能访问,不过很少出现多个任务或中断接收同一个通讯对象的情况

3.发送通知的任务不能进入阻塞
只有等待通知的任务可以被阻塞,发送通知的任务,在任何情况下都不会因为发送失败而进入阻塞态,像队列:写队列当队列满的时候,可以进入阻塞态

4.通知值只有一个32位的无符号的整形
加粗样式不像队列,可以缓存多个任意类型的数据,而任务通知只有一个消息,而且只能作用一次(接收到通知值等待通知的任务才能被唤醒)

接下来就开始分析任务通知有关函数的源码,其中会穿插着讲解用任务通知模拟出来的队列、信号量、事件组与真实的有何区别。

二、任务通知源码分析

任务通知的创建就不用说了,任务被创建时则就便有了任务通知,而且FreeRTOS默认任务通知是开启的。

1.发送通知函数xTaskGenericNotify

FreeRTOS定义了三个发送通知的函数,其实他们都是宏定义最终调用的是xTaskGenericNotify(),只不过他们的传入的参数有所区别,这都是FreeRTOS的老套路了,所以我们先分析完xTaskGenericNotify()函数的实现,再谈谈这三个函数应用上有何区别。
在这里插入图片描述
1.xTaskGenericNotify()函数原型:
在这里插入图片描述

  • 函数参数:
    1.xTaskToNotify:传入接收任务通知的任务控制块
    2.uxIndexToNotify:任务的指定通知(任务通知相关数组下标,默认为0,使用数组第一个元素当做通知)
    在这里插入图片描述
    3.ulValue:要写入的通知值
    4.eAction:通知的方式(模拟信号量,消息队列、事件组中方式),可取的值如下所示
    在这里插入图片描述
    第一个取值:只起通知作用也是有用的,至少可以唤醒,因未等待到通知而阻塞的任务。

5.pulPreviousNotificationValue:用于获取发送通知前的通知值

  • 函数返回值
    pdPASS 任务通知发送成功
    pdFAIL 任务通知发送失败

2.TaskGenericNotify()源码分析:

#if ( configUSE_TASK_NOTIFICATIONS == 1 )

    BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify,
                                   UBaseType_t uxIndexToNotify,
                                   uint32_t ulValue,
                                   eNotifyAction eAction,
                                   uint32_t * pulPreviousNotificationValue )
    {
        TCB_t * pxTCB;
        BaseType_t xReturn = pdPASS;
        uint8_t ucOriginalNotifyState;

        configASSERT( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES );
        configASSERT( xTaskToNotify );
        pxTCB = xTaskToNotify;

        taskENTER_CRITICAL();
        {
            /* 判断是否需要通知前的通知值 */
            if( pulPreviousNotificationValue != NULL )
            {
               /* 获取发送通知前的通知值 */
                *pulPreviousNotificationValue = pxTCB->ulNotifiedValue[ uxIndexToNotify ];
            } 
			/* 记录发送通知前的任务通知状态 */
            ucOriginalNotifyState = pxTCB->ucNotifyState[ uxIndexToNotify ];
            /* 将要接收的通知的任务的状态设置为等待接收通知状态 */
            pxTCB->ucNotifyState[ uxIndexToNotify ] = taskNOTIFICATION_RECEIVED;

            switch( eAction )
            {
               /* 模拟事件组:将通知值的某些位置一 */
                case eSetBits:
                    pxTCB->ulNotifiedValue[ uxIndexToNotify ] |= ulValue;
                    break;
               /* 模拟计数型信号量:将通知值的某些位置一 */
                case eIncrement:
                    ( pxTCB->ulNotifiedValue[ uxIndexToNotify ] )++;
                    break;
               /* 模拟队列:覆写通知值 */
                case eSetValueWithOverwrite:
                    pxTCB->ulNotifiedValue[ uxIndexToNotify ] = ulValue;
                    break;
				/* 模拟队列:(不覆盖)写通知值 */
                case eSetValueWithoutOverwrite:
                    /* 如果任务状态不处于等待接收状态,说明通知值已被读走,
                       可以写入*/
                    if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
                    {
                        pxTCB->ulNotifiedValue[ uxIndexToNotify ] = ulValue;
                    }
                    else
                    {
                        /* 通知值未被读走,不能覆写 */
                        xReturn = pdFAIL;
                    }

                    break;

                case eNoAction:

                    /* 只将任务标记为等待接收通知状态
                       并不修改通知值 */
                    break;

                default:

                    /* Should not get here if all enums are handled.
                     * Artificially force an assert by testing a value the
                     * compiler can't assume is const. */
                    configASSERT( xTickCount == ( TickType_t ) 0 );

                    break;
            }

            traceTASK_NOTIFY( uxIndexToNotify );

            /* 如果在此之前,任务因等待任务通知而被阻塞(该任务为等待通知状态),则现在解除阻塞 */
            if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
            {
                /* 将任务从所在任务状态列表(延时列表)中移除 */
                listREMOVE_ITEM( &( pxTCB->xStateListItem ) );
				/* 将任务添加到就绪任务列表中 */
                prvAddTaskToReadyList( pxTCB );

                /* 该任务不应在事件列表中 */
                configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );

                #if ( configUSE_TICKLESS_IDLE != 0 )
                    {
                        /* 更新下一个解除阻塞的任务 */
                        prvResetNextTaskUnblockTime();
                    }
                #endif
				/* 有任务解除阻塞后,就应该判断是否需要进行任务切换 */
                if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
                {
					/* 悬起 PendSV中断,准备进行任务切换 */
                    taskYIELD_IF_USING_PREEMPTION();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        taskEXIT_CRITICAL();

        return xReturn;
    }

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

在这里插入图片描述
源码解析:
1.如果传入的pulPreviousNotificationValue不为NULL(就是一个32位变量的地址),则代表需要获取发送通知前的通知值。
在这里插入图片描述
2.这里解释一下为什么要将任务的通知状态改为等待接收通知状态
首先要明白一点我们改的是要接收通知的任务通知的状态,则当调用接收通知函数时,判断一下任务的通知状态是不是等待接收通知状态如果是那说明有通知已经发送过来了。

在这里插入图片描述
3.解释一下框中的内容
不能覆写:代表已经有通知值,说明前面已经调用过一次发送通知函数xTaskGenericNotify,将任务的通知状态改为等待接收通知,如果再一次调用xTaskGenericNotify去发送通知,发送这次的任务通知状态已经不等于等待接收通知了,说明通知值被取走(其中调用过接收通知函数,会将任务的状态改写,讲接收通知函数你就知道了)。
在这里插入图片描述
4.如果任务为等待通知状态,说明该任务在此之前已经调用过接收通知函数(如果没有通知,会将任务的通知状态改写成等待通知状态,并进入阻塞态),此时我正好发送通知过去,就需要唤醒该任务去取通知值。
在这里插入图片描述
当然光看一个发送通知函数,可能还是不太理解这些通知状态,所以一定是要发送/接收通知函数配合起来看,才能连贯起来,就豁然开朗。

函数 xTaskNotify():
此函数用于往指定任务发送任务通知,通知方式可以自由指定,并且不获取发送任务通知前任务通知的通知值。
函数 xTaskNotifyAndQuery():
此函数用于往指定任务发送任务通知,通知方式可以自由指定,并且获取发送任务通知前任务通知的通知值。

函数 xTaskNotifyGive():
此函数用于往指定任务发送任务通知,通知方式为将通知值加 1,并且不获取发送任务通知前任务通知的通知值(用于二值/计数型信号量)

在这里插入图片描述
当然中断也可以向某任务发送通知值,函数跟上面的差不多,只不过多了中断保护。

2.接收任务通知 ulTaskNotifyTake()

ulTaskNotifyTake()函数其实是一个宏真正调用的是ulTaskGenericNotifyTake()函数,该函数就是专门服务与模拟二值信号量/计数型信号量的。
在这里插入图片描述
1.ulTaskNotifyTake()函数原型
在这里插入图片描述

  • 函数参数

1.uxIndexToWaitOn :任务的指定通知(任务通知相关数组下标)
2.xClearCountOnExit: 在成功接收通知后,将通知值清零或减 1(分别对应二值信号量,计数型信号量)
3.xTicksToWait: 阻塞等待任务通知值的最大时间

  • 函数返回值
    0:接收失败
    非 0: 接收成功,返回任务通知的通知值(当前计数值)

2.ulTaskNotifyTake()函数源码

#if ( configUSE_TASK_NOTIFICATIONS == 1 )

    uint32_t ulTaskGenericNotifyTake( UBaseType_t uxIndexToWait,
                                      BaseType_t xClearCountOnExit,
                                      TickType_t xTicksToWait )
    {
        uint32_t ulReturn;

        configASSERT( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES );

        taskENTER_CRITICAL();
        {
            /* 通知值为0代表没有接收到通知 */
            if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] == 0UL )
            {
                /* 将任务通知的状态设置为等待通知状态 */
                pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskWAITING_NOTIFICATION;

			    /* 如果设置了等待时间 */
                if( xTicksToWait > ( TickType_t ) 0 )
                {
                    /* 将当前任务添加到阻塞态任务列表 */
                    prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                    traceTASK_NOTIFY_TAKE_BLOCK( uxIndexToWait );

                    /* 悬起 PendSV中断 准备进行任务切换 */
                    portYIELD_WITHIN_API();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        taskEXIT_CRITICAL();

		/* 任务如果进入阻塞,在这段时间里,任务可能被
		   发送通知的函数唤醒,唤醒则继续往下执行 */

        taskENTER_CRITICAL();
        {
           /* 代码执行到这里有三种情况
            1.一直没有接收到通知,任务阻塞超时被唤醒。
            2.一进该函数通知值就不等于0,说明有通知,任务也不需要阻塞。
            3.任务因没通知而阻塞,但是在该任务阻塞期间
             有其他任务向该任务发送了通知,并唤醒该任务。*/
            
            traceTASK_NOTIFY_TAKE( uxIndexToWait );
			/* 再次获取任务通知的通知值,如果等于0说明接收通知失败*/
            ulReturn = pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ];

            if( ulReturn != 0UL )
            {
                /* 接收通知成功
                xClearCountOnExit == pdTRUE  通知值清0 : 二值信号量
                xClearCountOnExit == pdFALSE 通知值减一 :计数信号量*/
                if( xClearCountOnExit != pdFALSE )
                {
                    pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] = 0UL;
                }
                else
                {
                    pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] = ulReturn - ( uint32_t ) 1;
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }	
			/* 不论接收通知成功或者失败,都将任务通知的状态标记为未等待通知状态 */
            pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION;
        }
        taskEXIT_CRITICAL();

        return ulReturn;
    }

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

在这里插入图片描述
源码分析:
1.如果任务没有通知的情况下,调用了接收通知函数,则将任务通知状态设置为等待通知状态,这样等调用发送通知函数的时候,就方便去唤醒该任务(有通知了,唤醒该任务去接收通知做后续处理)。
在这里插入图片描述
2.下图也印证了上面发送通知函数的是否可以覆写的问题
在这里插入图片描述
用任务通知模拟的二值或者计数型信号量与真实的有何区别?
真实的计数型信号量可以指定初始值,且有最大值,而模拟的初始值为0且不能设置最大值。

自己对比一下:
FreeRTOS信号量详解

3.接收任务通知函数xTaskNotifyWait()

该函数一般用来模拟队列或者事件组的接收,该函数可以在等待前和成功等待到任务通知后清除通知指定位,与消息队列不同的是在任务等待超时后任务通仍然可以获取通知值。但假设用该函数获取了一次通知值,但是没有清除通知值,等下次又调用该函数时会直接进入阻塞(因为判断是否有通知不是取决于通知是否不等于0(当然模拟信号量的确实以是否为0作为是否有通知的标准),而是别的任务发送通知到该任务)。

当然xTaskNotifyWait()函数只是一个宏,真正调用的是xTaskGenericNotifyWait()函数.

在这里插入图片描述
1.xTaskGenericNotifyWait()函数原型:
在这里插入图片描述

  • 函数参数
    1.uxIndexToWaitOn :任务的指定通知(任务通知相关数组下标)
    2.ulBitesToClearOnEntry: 等待前指定清零的任务通知通知值比特位
    3.ulBitesToClearOnExit :成功等待后指定清零的任务通知通知值比特位
    4.pulNotificationValue :要获取的通知值(队列消息或者事件组)
    5.xTicksToWait :阻塞等待任务通知值的最大时间

  • 函数返回值
    pdTRUE:等待任务通知成功
    pdFALSE:等待任务通知失败

xTaskGenericNotifyWait()函数源码:

/*-----------------------------------------------------------*/

#if ( configUSE_TASK_NOTIFICATIONS == 1 )

    BaseType_t xTaskGenericNotifyWait( UBaseType_t uxIndexToWait,
                                       uint32_t ulBitsToClearOnEntry,
                                       uint32_t ulBitsToClearOnExit,
                                       uint32_t * pulNotificationValue,
                                       TickType_t xTicksToWait )
    {
        BaseType_t xReturn;
        /* 不能数组越界 */
        configASSERT( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES );

        taskENTER_CRITICAL();
        {
            /* 若不为等待接收通知状态,说明其他任务没有发送通知给该任务
               如果设置了超时时间,则任务需要进入阻塞态 */
            if( pxCurrentTCB->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED )
            {
                /* 等待通知前清除任务通知值中的位,因为通知任务或中断可能会设置位。 这可用于将值清除为零。 */
                pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] &= ~ulBitsToClearOnEntry;

				/* 设置任务通知的状态为等待通知状态 */
                pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskWAITING_NOTIFICATION;
                /* 如果允许阻塞 */
                if( xTicksToWait > ( TickType_t ) 0 )
                {
                
				    /* 设置任务通知的状态为等待通知状态 */
                    prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                    traceTASK_NOTIFY_WAIT_BLOCK( uxIndexToWait );

                    /* 悬起 PendSv中断,准备进行任务切换*/
                    portYIELD_WITHIN_API();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        taskEXIT_CRITICAL();

		/* 如果该任务被阻塞了,解除阻塞后继续从这往下执行 */ 
		 
        taskENTER_CRITICAL();
        {
            traceTASK_NOTIFY_WAIT( uxIndexToWait );
            /* 当代码执行到这里可能是以下三种情况:
               1.前面的判断不成立,一进来就有通知任务不需要进入阻塞 
               2.前面的判断成立,任务进入阻塞,但是有其他任务向该任务发送
               通知并将该任务唤醒 
               3.前面的判断处理,任务进入阻塞,但是阻塞超时                 任务被迫唤醒       
            */
               
            if( pulNotificationValue != NULL )
            {
                /* 输出当前通知值,该值可能已更改,也可能未更改
                   未更改说明是任务是超时被唤醒的此时虽然能获取通知值
                   但是通知值是上次的,其实是获取通知值失败的 */
                *pulNotificationValue = pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ];
            }

            /*如果设置了 ucNotifyValue,则任务从未进入阻止状态
            (因为通知已挂起)或任务由于通知被唤醒。 
            否则,任务由于超时而解除阻止 */
            
            /* 如果任务通知的状态还不等于等待接收通知状态的话
            说明任务还是没有接收到通知任务只不过是超时被唤醒*/
            if( pxCurrentTCB->ucNotifyState[ uxIndexToWait ] != taskNOTIFICATION_RECEIVED )
            {
                /* A notification was not received. */
                xReturn = pdFALSE;
            }
            else
            {
				/* 在成功接收到通知后将通知值的指定比特位清零 */
                pxCurrentTCB->ulNotifiedValue[ uxIndexToWait ] &= ~ulBitsToClearOnExit;
                xReturn = pdTRUE;1
            }
            /* 不论接收通知成功或者失败都将任务通知的状态标记为未等待通知状态*/
            pxCurrentTCB->ucNotifyState[ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION;
        }
        taskEXIT_CRITICAL();

        return xReturn;
    }

#endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/

在这里插入图片描述
源码我就分析了,直接看代码注释,一定要接收/发送两个通知函数一起分析,这样理解起来轻松多了,然后再对比一下ulTaskNotifyTake()与xTaskNotifyWait函数有何区别,其实他们最大的区别就是服务对象不一样,前者为模拟信号量服务,后着为队列,事件组服务。

1.模拟的队列与真实的队列有何区别?
(1).真实的队列可以容纳多个数据而且数据大小可以指定,而任务通知只有一个数据(32位的无符号整数)
(2).真实的队列,写队列时可以阻塞,任务通知则不能

与事件组的区别:
其实你真正看懂源码,区别显而易见,留给你们的作业,哈哈哈哈哈哈哈
事件组详解

三.总结

发现学通了,都是有套路的,FreeRTOS全程都是一个风格,还怕研究不透嘛,只需将源码学透,接下来应用就是熟练度的问题了。

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

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

相关文章

Spring Security入门

1. Spring Security 简介 Spring Security 是一个高度可定制的身份验证和访问控制框架&#xff0c;它基于 Spring 框架&#xff0c;并可与 Spring 全家桶无缝集成。该框架可以精确控制用户对应用程序的访问&#xff0c;控制用户的角色和权限等。 Spring Security 最早是由 Be…

C Primer Plus第三章编程练习答案

学完C语言之后&#xff0c;我就去阅读《C Primer Plus》这本经典的C语言书籍&#xff0c;对每一章的编程练习题都做了相关的解答&#xff0c;仅仅代表着我个人的解答思路&#xff0c;如有错误&#xff0c;请各位大佬帮忙点出&#xff01; 1.通过试验&#xff08;即编写带有此类…

第三节 HLMSEditor场景编辑器的编译

本节注意介绍下HLMSEditor场景编辑器的源码编译使用 一 安装依赖的资源 使用编译器为VS2019 X64&#xff0c;操作系统为WIN10&#xff0c;Ogre2.1&#xff0c;HLMSEditor 注意&#xff1a;为什么不用Ogre2.3?因为HLMSEditor版本为0.5.5&#xff0c;很久没有更新了&#xff0…

【Linux进阶之路】yum与vim操作

文章目录 前言一.yum——Linux的应用商店介绍基本使用① yum源②安装数据传输软件1.将Linux的文件传输到Windows平台上2.将Windows的文件传到Linux系统上 ③删除数据传输软件⑥查看安装包版本⑤练习安装与卸载小火车安装与卸载牛会说话 二.vim —— 一款优雅的编辑器①基本模式…

安卓基础巩固(一):工程结构、基本概念、常用布局、基本组件、动画

文章目录 安卓项目结构AndroidMainfest.xmlres资源目录简介 基本概念LayoutR类 Application与ActivityContextIntent数据传递可传递的数据类型intent.putExtra&#xff08;&#xff09;和使用Bundle的区别数据传递大小的限制 通过Intent 过滤器接收隐式 Intent&#xff1a; 单位…

国内免费的Chatgpt网站分享 支持Ai对话绘图

Chatgpt正式进入大众视野&#xff0c;已半年有余&#xff0c;作为一款媲美于百度、谷歌搜索的工具&#xff0c;它已经成为我们工作、生活、学习中不可缺少的左膀右臂&#xff0c;相比于搜索引擎&#xff0c;它寻找答案&#xff0c;不再需要自己在众多模糊不定的结果中寻找自己需…

【生物信息】调控基因组学 (Regulatory Genomics) 和Deep CNN

文章目录 Regulatory GenomicsBiological motivation of Deep CNNMulti-task CNN 来自Manolis Kellis教授&#xff08;MIT计算生物学主任&#xff09;的课《人工智能与机器学习》 主要内容就是调控基因组学和深度卷积网络的结合 由于这部分在我学习的课程中内容很少&#xff0c…

使用虚拟机安装ikuai软路由系统,搭建pppoe拨号服务器

搭建pppoe拨号服务器 一、搭建ikuai软路由系统1、VMware版本2、ikuai官网上下载系统镜像3、使用虚拟机安装ikuai系统4、登录ikuai管理界面 二、安装win7虚拟机验证拨号功能三、其他电脑要使用这个pppoe虚拟机进行拨号怎么办呢&#xff1f; 一、搭建ikuai软路由系统 先说一下背景…

【C++/嵌入式笔试面试八股】一、11.C内存分配/堆栈

C内存分配/堆栈 01.C内存分配❤️ #include <stdio.h>const int g_A = 10; //常量区 int g_B = 20; //数据段 static<

冲冲冲冲冲

目录 java基础 面向对象 集合 线程 异常 IO 反射 MySQL SpringMVC 1.SpringMVC常用的注解有哪些&#xff1f; 2.说说你对Spring MVC的理解 Spring 1. spring是什么&#xff1f; 2.Autowired和Resource关键字的区别&#xff1f; 3.说说你对Spring的IOC是怎么理解的…

计算机硬件系统 — 冯诺依曼体系结构运行原理解析

目录 文章目录 目录计算机系统计算机硬件系统&#xff08;冯诺依曼体系结构&#xff09;PC 主机硬件CPU&#xff08;中央处理器&#xff09;CPU 的组成部分CPU 总线控制器单元运算器单元寄存器组超线程与多核架构三级高速缓存为什么需要缓存三级缓存结构 CPU 的指令集指令集的类…

IIS6.0 put文件上传GetShell

目录 WebDAV 环境配置 漏洞复现 漏洞修复 WebDAV WebDAV &#xff08;Web-based Distributed Authoring and Versioning&#xff09; 是一种HTTP1.1的扩展协议。它扩展了HTTP 1.1&#xff0c;在GET、POST、HEAD等几个HTTP标准方法以外添加了一些新HTTP请求方法&#xff0c…

生成模型(自编码器、VAE、GAN)

文章目录 自编码器Autoencoder潜在表示&#xff08;latent representation&#xff09;VAE迁移学习 生成对抗网络GAN李沐论文精读摘要导言相关工作Adversarial net简单总结 精读挖坑&#xff08;上课内容 来自Manolis Kellis教授&#xff08;MIT计算生物学主任&#xff09;的课…

14种UML图(统一建模语言)

目录 1.简述2.UML组成3.UML事物4.UML关系5.UML图5.1 UML图的分类5.2 结构图&#xff08;静态图&#xff09;1&#xff09;类图2&#xff09;对象图3&#xff09;构件图4&#xff09;部署图5&#xff09;制品图6&#xff09;包图7&#xff09;复合结构图 5.3 行为图&#xff08;…

k8s进阶4——安全机制常用工具之kube-beach、kube-hunter、Trivy、kubesec

文章目录 一、K8s安全机制二、kube-beach工具2.1 安装2.2 工具使用2.2.1 改成INFO状态2.2.2 改成pass状态 三、kube-hunter工具四、Trivy镜像漏洞扫描工具五、kubesec检查YAML文件安全配置 一、K8s安全机制 基本了解&#xff1a; 我们在前面学习的安全控制RBAC就属于K8s安全机制…

【Midjourney】Midjourney Prompt 提示词 ② ( 怀旧像素风 | 物体 A 被物体 B 包围 | 折纸艺术风格 )

文章目录 一、8-bit 16bit 提示词 - 怀旧像素风二、A out of B 提示词 - 物体 A 被物体 B 包围三、layered paper 提示词 - 折纸艺术风格 一、8-bit 16bit 提示词 - 怀旧像素风 使用 8-bit 16-bit 提示词 , 可以绘制出 像素游戏风格的图像 , 如下图所示 ; 该提示词适合创作与游…

Linux Web服务(HTTP HTML DNS)

DNS 域名解析 DNS负责将域名转换为IP地址。 详细的介绍在之前的博客中有详细记录。 这里回顾一下DNS的解析过程。 域名结构 主机名.子域.[二级域].顶级域.(根域) DNS 解析过程&#xff08;面试题&#xff09; 客户端 -> 本地缓存域名服务器 -> 根域服务器 -> 二级域服…

测试分析流程及输出项

测试分析 一、确认测试范围 根据测试项目的不同需求&#xff0c;有大致几类测试项目类型&#xff1a;商户平台功能测试、支付方式接入测试、架构调整类测试、后台优化测试、性能测试、基本功能自动化测试。 测试项目需要按照文档要求进行测试需求分析&#xff0c;并给出对应…

NIFI1.21.0最新版本安装_采用HTTP方式_搭建集群_实际操作---大数据之Nifi工作笔记0050

这里要提一嘴...看中文的,视频或者文档虽然学习会快一点,但是... 有的时候一些新的东西没有中文的,还是得看英文的...时间就了就好了,要不然解决不了问题 英文写的,凡是好东西,肯定是很详细的,并且就是为了让别人弄明白,做了大量解释,所以不用担心看不懂... 首先,把安装包,上…

Java的Arrays类的sort()方法(41)

目录 sort&#xff08;&#xff09;方法 1.sort&#xff08;&#xff09;方法的格式 2.使用sort&#xff08;&#xff09;方法时要导入的类 3.作用 4.作用的对象 5.注意 6.代码及结果 &#xff08;1&#xff09;代码 &#xff08;2&#xff09;结果 sort&#xff08;&…