FreeRTOS-任务通知源码分析

2023-05-16

任务通知可用来代替信号量、消息队列、事件标志位,而且使用任务通知的形式效率会更高,它不需要像信号量那样创建队列和操作队列,任务通知的存储变量来自任务控制块中,当宏 configUSE_TASK_NOTIFICATIONS 被定义为1时就可以使用任务通知相关的函数了。任务通知的接口函数同样存在发送和接收,发送的接口函数如下:

/* 发送通知,有通知值但不保留接收任务原通知值 */
xTaskNotify( xTaskToNotify, ulValue, eAction )
xTaskNotifyFromISR(xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken)

/* 发送通知(可代替计数型信号量),没有通知值并且不保留接收任务的通知值,会将接收任务的通知值加一 */
xTaskNotifyGive(xTaskToNotify)
vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )

/* 发送通知,有通知值并且保留接收任务的原通知值 */
xTaskNotifyAndQuery(xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue)
xTaskNotifyAndQueryFromISR(xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken)

这几个发送通知的接口实际上都是宏,定义如下:

#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL )
#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )

#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotifyValue ) )
#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )

有分任务之间的接口和中断的接口,核心主要就是这两个函数:

	BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
	BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )

任务通知的写入方式有以下几种,使用一个枚举来定义:

typedef enum
{
	eNoAction = 0,				/* 不升级通知值 */
	eSetBits,					/* 更新指定的bit */
	eIncrement,					/* 通知值加一 */
	eSetValueWithOverwrite,		/* 覆写的方式更新通知值 */
	eSetValueWithoutOverwrite	/* 不覆盖通知值 */
} eNotifyAction;

xTaskGenericNotify 通用通知函数的源码分析如下:

#if( configUSE_TASK_NOTIFICATIONS == 1 )

	/* 形参:
	 * 	xTaskToNotify:任务句柄(要通知的任务)
	 * 	ulValue:任务通知值
	 * 	eAction:任务通知更新的方法
	 * 	pulPreviousNotificationValue:用于保存任务更新前的任务通知值
	 */
	BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
	{
	TCB_t * pxTCB;
	BaseType_t xReturn = pdPASS;
	uint8_t ucOriginalNotifyState;

		configASSERT( xTaskToNotify );
		pxTCB = xTaskToNotify;

		/* 进入临界区 */
		taskENTER_CRITICAL();
		{
			if( pulPreviousNotificationValue != NULL )
			{
				/* 形参作为返回值,返回值空间有效,返回任务的原通知值 */
				*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
			}

			/* 获取被通知任务原来的状态 */
			ucOriginalNotifyState = pxTCB->ucNotifyState;

			/* 更新被通知任务的状态为接收 */
			pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;

			/* 判断任务通知的更新方法 */
			switch( eAction )
			{
				case eSetBits	:
					/* 用做二值信号量 */
					pxTCB->ulNotifiedValue |= ulValue;
					break;

				case eIncrement	:
					/* 用做计数型信号量 */
					( pxTCB->ulNotifiedValue )++;
					break;

				case eSetValueWithOverwrite	:
					/* 覆写的方式写入数据 */
					pxTCB->ulNotifiedValue = ulValue;
					break;

				case eSetValueWithoutOverwrite :
					/* 不覆盖方式写入数据 */
				
					if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
					{
						/* 被通知任务的状态不处于接收状态的话直接赋值 */
						pxTCB->ulNotifiedValue = ulValue;
					}
					else
					{
						/* 如果任务处于接收状态的话就不能被写入,因为使用的不覆写的方式,返回错误 */
						xReturn = pdFAIL;
					}
					break;

				case eNoAction:
					break;

				default:
					configASSERT( pxTCB->ulNotifiedValue == ~0UL );

					break;
			}

			traceTASK_NOTIFY();

			/* 如果被通知任务原来的状态为等待通知而进入阻塞,这里解锁阻塞 */
			if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
			{
				/* 将任务从原来的状态列表中移除 */
				( void ) uxListRemove( &( pxTCB->xStateListItem ) );
				/* 将任务添加到就绪列表中 */
				prvAddTaskToReadyList( pxTCB );

				configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );

				#if( configUSE_TICKLESS_IDLE != 0 )
				{
					prvResetNextTaskUnblockTime();
				}
				#endif

				/* 如果任务的优先级高于当前优先级则进行一次任务切换 */
				if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
				{
					taskYIELD_IF_USING_PREEMPTION();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		/* 退出临界区 */
		taskEXIT_CRITICAL();

		return xReturn;
	}

#endif /* configUSE_TASK_NOTIFICATIONS */

在中断中使用的发送函数 xTaskGenericNotifyFromISR 分析如下:

#if( configUSE_TASK_NOTIFICATIONS == 1 )

	/* 形参:
	 * 	xTaskToNotify:任务句柄
	 * 	ulValue:任务通知值
	 * 	eAction:任务通知更新的方法
	 * 	pulPreviousNotificationValue:用于保存任务更新前的任务通知值
	 *	pxHigherPriorityTaskWoken:使用变量记退出此函数以后是否进行任务切换,用于需要提供一个变量来保存这个值
	 */
	BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
	{
	TCB_t * pxTCB;
	uint8_t ucOriginalNotifyState;
	BaseType_t xReturn = pdPASS;
	UBaseType_t uxSavedInterruptStatus;

		configASSERT( xTaskToNotify );

		portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
		pxTCB = xTaskToNotify;

		/* 进入中断临界区 */
		uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
		{
			if( pulPreviousNotificationValue != NULL )
			{
				/* 形参作为返回值,返回值空间有效,返回任务的原通知值 */
				*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
			}

			/* 获取被通知任务原来的状态 */
			ucOriginalNotifyState = pxTCB->ucNotifyState;
			/* 更新被通知任务的状态为接收 */
			pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;

			/* 判断任务通知的更新方法 */
			switch( eAction )
			{
				case eSetBits	:
					/* 用做二值信号量 */
					pxTCB->ulNotifiedValue |= ulValue;
					break;

				case eIncrement	:
					/* 用做计数型信号量 */
					( pxTCB->ulNotifiedValue )++;
					break;

				case eSetValueWithOverwrite	:
					/* 覆写的方式写入数据 */
					pxTCB->ulNotifiedValue = ulValue;
					break;

				case eSetValueWithoutOverwrite :
					/* 不覆盖方式写入数据 */
				
					if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
					{
						/* 被通知任务的状态不处于接收状态的话直接赋值 */
						pxTCB->ulNotifiedValue = ulValue;
					}
					else
					{
						/* 如果任务处于接收状态的话就不能被写入,返回错误 */
						xReturn = pdFAIL;
					}
					break;

				case eNoAction :
					break;

				default:
					configASSERT( pxTCB->ulNotifiedValue == ~0UL );
					break;
			}

			traceTASK_NOTIFY_FROM_ISR();

			/* 如果被通知任务原来的状态为等待通知而进入阻塞,这里解锁阻塞 */
			if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
			{
				configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );

				/* 如果调度器休眠没休眠,执行这个分支 */
				if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
				{
					/* 将任务从原来的状态列表中移除 */
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );
					/* 将任务添加到就绪列表中 */
					prvAddTaskToReadyList( pxTCB );
				}
				/* 如果调度器休眠了,执行这个分支 */
				else
				{
					/* 将任务插入到挂机就绪列表,调度器恢复后再放入就绪列表 */
					vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
				}

				/* 如果任务的优先级高于当前优先级则进行一次任务切换 */
				if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
				{
					if( pxHigherPriorityTaskWoken != NULL )
					{
						/* 返回告知需要进行一次任务切换 */
						*pxHigherPriorityTaskWoken = pdTRUE;
					}
					xYieldPending = pdTRUE;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		/* 退出中断临界区 */
		portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

		return xReturn;
	}

#endif

下面获取任务通知的接口:

/* 获取任务通知,可以设置在退出此函数的时候将任务通知值清零或减一,用于代替二值信号和计数型信号量 */
ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait)

/* 获取任务通知,等待任务通知,比ulTaskNotifyTake强大,全功能版任务通知获取函数 */
xTaskNotifyWait(xTaskToNotify, ulValue, eAction)

ulTaskNotifyTake 的源码分析如下:

#if( configUSE_TASK_NOTIFICATIONS == 1 )

	/* 形参:
	 * 	xClearCountOnExit:为 pdFALSE 的话在退出时通知值减一,类似计数型信号量,
	 *					   为 pdTURE 的话在退出时通知值清零,类似二值信号量
	 * 	xTicksToWait:阻塞时间
	 */
	uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
	{
	uint32_t ulReturn;

		/* 进入临界区 */
		taskENTER_CRITICAL();
		{
			/* 如果当前任务通知值为0 */
			if( pxCurrentTCB->ulNotifiedValue == 0UL )
			{
				/* 任务的通知状态标记为等待通知 */
				pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

				/* 如果任务的等待时间大于0 */
				if( xTicksToWait > ( TickType_t ) 0 )
				{
					/* 将任务添加到延时任务列表 */
					prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
					traceTASK_NOTIFY_TAKE_BLOCK();

					/* 进行一次任务调度 */
					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		/* 退出临界区 */
		taskEXIT_CRITICAL();

		/* 进入临界区,执行到这里说明接收到了来自其它任务的通知或超时 */
		taskENTER_CRITICAL();
		{
			traceTASK_NOTIFY_TAKE();
			/* 获取当前任务的通知值 */
			ulReturn = pxCurrentTCB->ulNotifiedValue;

			/* 通知值不为0 */
			if( ulReturn != 0UL )
			{
				if( xClearCountOnExit != pdFALSE )
				{
					/* 类似二值信号量,获取到后清零 */
					pxCurrentTCB->ulNotifiedValue = 0UL;
				}
				else
				{
					/* 类似计数信号量,获取到后减一 */
					pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1;
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
			/* 当前任务的通知状态改为等待通知 */
			pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
		}
		/* 退出临界区 */
		taskEXIT_CRITICAL();

		return ulReturn;
	}

#endif

xTaskNotifyWait 源码分析如下:

#if( configUSE_TASK_NOTIFICATIONS == 1 )

	/* 形参:
	 *	ulBitsToClearOnEntry:进入函数时是否清除任务bit,没接收到任务通知的时候将任务
	 *						  通知值与此参数的取反值进行按位与运算,当此参数
	 *						  为0xffffffff时会将任务的通知值清零
	 * 	xClearCountOnExit:为 pdFALSE 的话在退出时通知值减一,类似计数型信号量,
	 *					   为 pdTURE 的话在退出时通知值清零,类似二值信号量
	 *	pulNotificationValue:用于保存任务通知值
	 * 	xTicksToWait:阻塞时间
	 */
	BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
	{
	BaseType_t xReturn;

		/* 进入临界区 */
		taskENTER_CRITICAL();
		{
			/* 当前任务的通知状态不是接收状态,即还没接收到任务通知 */
			if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
			{
				/* 清除指定的bit */
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;

				/* 任务的通知状态标记为等待通知 */
				pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

				/* 用户设置的超时时间大于0 */
				if( xTicksToWait > ( TickType_t ) 0 )
				{
					/* 将任务添加到延时列表中 */
					prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
					traceTASK_NOTIFY_WAIT_BLOCK();

					/* 进行一次任务调度 */
					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		/* 退出临界区 */
		taskEXIT_CRITICAL();
		
		/* 进入临界区,执行到这里说明接收到了来自其它任务的通知或超时 */
		taskENTER_CRITICAL();
		{
			traceTASK_NOTIFY_WAIT();

			/* 用户传入的用于保存通知值的变量不为空 */
			if( pulNotificationValue != NULL )
			{
				/* 返回任务当前通知值 */
				*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
			}

			/* 未接收到任务通知返回 pdFALSE */
			if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )			{

				xReturn = pdFALSE;
			}
			/* 接收到任务通知返回 pdTRUE */
			else
			{
				/* 清除指定的bit */
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
				xReturn = pdTRUE;
			}
			/* 任务的通知状态标记为等待通知 */
			pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
		}
		/* 退出临界区 */
		taskEXIT_CRITICAL();

		return xReturn;
	}

#endif 

关于任务通知的代码相对比较简单,都是通过直接赋值的形式,不存在像信号量那样的入队和出队过程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS-任务通知源码分析 的相关文章

  • FreeRTOS系列

    1 多任务系统 1 1 前后台系统 单片机裸机开发时 一般都是在main函数里面用while 1 做一个大循环来完成所有的处理 循环中调用相应的函数完成所需的处理 有时也需要在中断中完成一些处理 相对于多任务系统而言 这就是单人单任务系统也
  • 【FreeRtos学习笔记】STM32 CubeMx——Timers(定时器)

    目录 1 软件定时器 2 示例程序 2 1 例程功能 2 2 步骤 2 3 实验结果 2 4 函数讲解 1 软件定时器 定时器是MCU常用的外设 我们在学习各种单片机时必然会学习它的硬件定时器 但是 MCU自带的硬件定时器资源是有限的 而且
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • FreeRTOS记录(七、FreeRTOS信号量、事件标志组、邮箱和消息队列、任务通知的关系)

    我们在前面单独介绍过FreeRTOS的任务通知和消息队列 但是在FreeRTOS中任务间的通讯还有信号量 邮箱 事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 增加邮箱部分 任务通知发送消息 Demo 202
  • FreeRTOS 软件定时器的使用

    FreeRTOS中加入了软件定时器这个功能组件 是一个可选的 不属于freeRTOS内核的功能 由定时器服务任务 其实就是一个定时器任务 来提供 软件定时器是当设定一个定时时间 当达到设定的时间之后就会执行指定的功能函数 而这个功能函数就叫
  • FreeRTOS-内核控制函数

    FreeRTOS 内核控制函数 FreeRTOS中有一些内核函数 一般来说这些内核函数在应用层不会使用 但是内核控制函数是理解FreeRTOS中断的基础 接下来我们逐一分析这些内核函数 taskYIELD 该函数的作用是进行任务切换 这是一
  • 【FreeRTOS开发问题】FreeRTOS内存溢出

    FreeRTOS内存溢出 如下图所示 FreeRTOS编译完成后可以看到 系统提示无法分配内存到堆 Objects Template axf Error L6406E No space in execution regions with A
  • freertos————互斥锁

    线程安全 多线程程序处于一个多变的环境 可访问的全局变量和堆数据随时可能被其他的线程改变 多个线程同时访问一个共享数据 可能造成严重的后果 出现问题的是之前移植了一个freemodbus的从站 多个任务访问全局变量保持寄存器区 导致最后读出
  • STM32F103移植FreeRTOS必须搞明白的系列知识---2(FreeRTOS任务优先级)

    STM32F103移植FreeRTOS必须搞明白的系列知识 1 Cortex CM3中断优先级 STM32F103移植FreeRTOS必须搞明白的系列知识 2 FreeRTOS任务优先级 STM32F103移植FreeRTOS必须搞明白的系
  • 啊哈C的简单使用

    打开啊哈C 新建一个程序输出hello world include
  • 基于STM32的FreeRTOS学习之中断测试实验(五)

    记录一下 方便以后翻阅 本章内容是接着上一章节进行的实际演练 1 实验目的 FreeRTOS可以屏蔽优先级低于configMAX SYSCALL INTERRUPT PRIORITY的中断 不会屏蔽高于其的中断 本次实验就是验证这个说法 本
  • [FreeRTOS入门学习笔记]定时器

    定时器的使用步骤 1 定义一个handle xTimerCreate创建 2 启动定时器 在Task1中调用 通过队列通知守护任务来执行定时器任务 要再config头文件中定义守护任务相关配置 虽然定时器是在task1中启动 但是定时器的任
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • STM32 Freertos 添加 外部sram heap_5.c

    1 添加外部SRAM 初始化 2 添加heap 5 c 3 初始化heap 5 c 外部堆栈 Define the start address and size of the two RAM regions not used by the
  • FreeRTOS实时操作系统(三)任务挂起与恢复

    系列文章 FreeRTOS实时操作系统 一 RTOS的基本概念 FreeRTOS实时操作系统 二 任务创建与任务删除 HAL库 FreeRTOS实时操作系统 三 任务挂起与恢复 FreeRTOS实时操作系统 四 中断任务管理 FreeRTO
  • 再论FreeRTOS中的configTOTAL_HEAP_SIZE

    关于任务栈和系统栈的基础知识 可以参考之前的随笔 FreeRTOS 任务栈大小确定及其溢出检测 这里再次说明 define configTOTAL HEAP SIZE size t 17 1024 这个宏 官方文档解释 configTOTA
  • FreeRTOS 配置TICK_RATE_HZ

    我使用的是带有 5 4 版 FreeRTOS 的 MSP430f5438 我有一个有趣的问题 我无法弄清楚 基本上 当我将 configTICK RATE HZ 设置为不同的值时 LED 闪烁得更快或更慢 它应该保持相同的速率 我将 con
  • 有可用的 FreeRTOS 解释语言库吗?

    我在一家公司工作 该公司使用 FreeRTOS 为多个设备创建固件 最近 我们对新功能的要求已经超出了我们固件工程师的工作能力 但我们现在也无力雇用任何新人 即使进行微小的更改 也需要固件人员在非常低的级别上进行修改 我一直在为 FreeR
  • C++ freeRTOS任务,非静态成员函数的无效使用

    哪里有问题 void MyClass task void pvParameter while 1 this gt update void MyClass startTask xTaskCreate this gt task Task 204
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d

随机推荐

  • 【做题系统】后端设计

    目录 一 设计思路 1 项目背景 2 技术栈选择 二 系统设计 1 系统结构图 2 项目结构 3 数据建模 4 数据流图 5 主要流程图 三 问题及解决办法 1 实现安全登录 访问 2 数据库中的信息安全问题 3 Mybatis plus如
  • C/C++字符串查找函数

    C C 43 43 string库 xff08 string h xff09 提供了几个字符串查找函数 xff0c 如下 xff1a memchr在指定内存里定位给定字符strchr在指定字符串里定位给定字符strcspn返回在字符串str
  • ssh命令-manpage

    SSH Section User Commands 1 Index Return to Main Contents BSD mandoc NAME ssh OpenSSH SSH 客户端 远程登录程序 总览 SYNOPSIS ssh l l
  • 一小时做出Java实战项目——飞翔的小鸟

    学姐又来啦 xff0c 今日分享一个Java实战项目 飞翔的小鸟 相信大家都玩过这个游戏 xff0c 这个游戏陪伴了我们整整一个童年 xff0c 是我们青春的回忆 飞翔的小鸟 xff0c 游戏中玩家只需通过点击方向键操纵让小鸟避开绿色管道等
  • 搭建本地仓库源

    一 如何搭建仓库源 之前讲了定制ISO的方法 xff1a 使用chroot定制系统 xff0c 但有时候我们想自定义的安装包不在上游的仓库源中 xff0c 在我们本地应该怎么办呢 xff1f 如果我们将deb包拷贝到iso目录再安装有点过于
  • 节点操作案例

    1 下拉菜单 xff08 仿微博 xff09 lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt me
  • document获取对象的三种三方法

    Document对象中有几个常用的方法 xff0c 我们在Dom简介中提到过 说到获取JavaScript对象的方法 xff0c 最常用的可能就是getElementById了 xff0c 它是Document中最常用的获取对象的方式之一
  • 程序员,最关键的跨越是什么?做到了月薪可能翻上几番~

    黑马程序员视频库 播妞微信号 xff1a boniu236 传智播客旗下互联网资讯 学习资源免费分享平台 作为一名程序员 xff0c 最关键的跨越是什么 xff1f 从普通程序员进阶为熟练开发者 xff0c 从熟练开发者跃升到技术专家或架构
  • 黑马程序员:3分钟带你读懂C/C++学习路线

    随着互联网及互联网 43 深入蓬勃的发展 xff0c 经过40余年的时间洗礼 xff0c C C 43 43 俨然已成为一门贵族语言 xff0c 出色的性能使之成为高级语言中的性能王者 而在今天 xff0c 它又扮演着什么样重要的角色呢 x
  • 数据归一化

    原文链接 xff1a 从公式出发 xff1a 什么是模型收敛的有效方法 xff1f 大家好 xff0c 我是泰哥 数据归一化在模型收敛中起着至关重要的作用 xff0c 从经典机器学习到深度学习的数据归一化方法是如何一步步演变的呢 xff1f
  • 【Python面试】 说说Python变量、函数、类的命名规则?

    最近公众号新增加了一个栏目 xff0c 就是每天给大家解答一道Python常见的面试题 xff0c 反正每天不贪多 xff0c 一天一题 xff0c 正好合适 xff0c 只希望这个面试栏目 xff0c 给那些正在准备面试的同学 xff0c
  • ​LeetCode刷题实战46:全排列

    算法的重要性 xff0c 我就不多说了吧 xff0c 想去大厂 xff0c 就必须要经过基础知识和业务逻辑面试 43 算法面试 所以 xff0c 为了提高大家的算法能力 xff0c 这个公众号后续每天带大家做一道算法题 xff0c 题目就从
  • Android硬件访问服务-Service

    Android有四大组件 xff1a 一 Activity 二 Service 三 Broadcast Receiver 四 Content Provider Service是Android中一个类 xff0c 它是Android四大组件之
  • android6.0第三方APP获得设备节点的访问权限

    之前使用android4 4的系统进行开发时 system app xff08 系统自带APP xff09 目录下的 app 可以直接访问 dev 目录下的设备节点 xff0c Android 5 0 以后 xff0c 因为采取了 SEAn
  • U-boot取消或修改启动延时bootdelay

    在我们的实际项目中都希望uboot尽量能够快速启动 xff0c 这就涉及到uboot的裁剪工作 xff0c 由于裁剪的工作量和内容比较多 xff0c 这里暂不描述 但是uboot有个启动延时bootdelay xff0c 在我们进入linu
  • uboot启动分析第一阶段(start.S)

    前面分析了启动脚本 Makefile mkconfig xff0c 接下来就是uboot的start S这个启动代码了 xff0c 下面是本章的平台介绍 xff1a 单板 xff1a 迅为4412开发板 Exynos 4412 SDRAM
  • Android使用串口(基于android-serialport-api)

    运行平台 xff1a CPU xff1a 全志V40 Android版本 xff1a 6 0 1 关于安卓设备上使用串口 xff0c 谷歌官方在github上有提供代码实例 xff0c 里面有JNI的代码和串口API的java文件 xff0
  • FreeRTOS-启动任务调度器源码分析

    本章基于FreeRTOS的启动任务调度器源码分析 xff0c 后续将会上传其它我对FreeRTOS的源码分析过程及理解 xff0c 首先来认识一下任务调度器 任务调度器 xff1a 任务调度器主要用于实现任务的切换 xff0c 任务并不是我
  • FreeRTOS-任务创建源码分析

    任务创建是FreeRTOS系统启动的第一个步骤 xff0c 前面在启动调度器的时候先创建了空闲任务 xff0c 然后再由调度器跳到任务里面去执行 任务创建函数里面做了很多的工作 xff0c 先会为任务堆栈和任务控制块分配内存并初始化它们 x
  • FreeRTOS-任务通知源码分析

    任务通知可用来代替信号量 消息队列 事件标志位 xff0c 而且使用任务通知的形式效率会更高 xff0c 它不需要像信号量那样创建队列和操作队列 xff0c 任务通知的存储变量来自任务控制块中 xff0c 当宏 configUSE TASK