运维最新FreeRTOS学习笔记---------队列(2),年薪60W必备

为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!

这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。

本份面试集锦涵盖了

  • 174 道运维工程师面试题
  • 128道k8s面试题
  • 108道shell脚本面试题
  • 200道Linux面试题
  • 51道docker面试题
  • 35道Jenkis面试题
  • 78道MongoDB面试题
  • 17道ansible面试题
  • 60道dubbo面试题
  • 53道kafka面试
  • 18道mysql面试题
  • 40道nginx面试题
  • 77道redis面试题
  • 28道zookeeper

总计 1000+ 道面试题, 内容 又全含金量又高

  • 174道运维工程师面试题

1、什么是运维?

2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

3、现在给你三百台服务器,你怎么对他们进行管理?

4、简述raid0 raid1raid5二种工作模式的工作原理及特点

5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

7、Tomcat和Resin有什么区别,工作中你怎么选择?

8、什么是中间件?什么是jdk?

9、讲述一下Tomcat8005、8009、8080三个端口的含义?

10、什么叫CDN?

11、什么叫网站灰度发布?

12、简述DNS进行域名解析的过程?

13、RabbitMQ是什么东西?

14、讲一下Keepalived的工作原理?

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

#define QUEUE_LENGTH        10
#define ITEM_SIZE           sizeof(uint8_t)   // 根据实际类型选择

StaticQueue_t xQueueBuffer;   // 保存队列结构体

uint8_t ucQueueStorage[QUEUE_LENGTH * ITEM_SIZE];  // 队列的buf

QueueHandle_t xQueue1 = xQueueCreateStatic( QUEUE_LENGTH, 
                                            ITEM_SIZE,
                                            ucQueueStorage,
                                            &xQueueBuffer );

QueueHandle_t xQueue2 = xQueueCreate( QUEUE_LENGTH, 
                                      ITEM_SIZE);

队列的读写函数如下所示:

// 写入
BaseType_t xQueueSend(QueueHandle_t xQueue,
                      const void * const pvItemToQueue,
                      TickType_t xTicksToWait);
// #define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) \
    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )

BaseType_t xQueueSendToBack(QueueHandle_t xQueue,
                      const void * const pvItemToQueue,
                      TickType_t xTicksToWait);
// #define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) \
    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )

BaseType_t xQueueSendToFront(QueueHandle_t xQueue,
                      const void * const pvItemToQueue,
                      TickType_t xTicksToWait);
//#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) \
    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )

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

xQueue表示要读取或写入的队列,xTicksToWait表示等待时间。

使用队列实现同步与互斥

基本原理:队列的阻塞访问(中断的关闭与开启,链表的使用

使用队列实现同步的示例代码如下:

/*
 * Configure the clocks, GPIO and other peripherals as required by the demo.
 */
static void prvSetupHardware( void );

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

void vmainTask1Function( void * param);
void vmainTask2Function( void * param);

/*-----------------------------------------------------------*/
UBaseType_t task1Run = 0;
UBaseType_t task2Run = 0;
UBaseType_t taskidleRun = 0;

TaskHandle_t xTask1Handle, xTask2Handle;

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

	prvSetupHardware();
	
	printf("Hello world!\r\n");
	
	xQueueHandle = xQueueCreate(1, sizeof(int));
	if(0 == xQueueHandle) {
		  printf("create queue failed!\r\n");
	}
	
	xTaskCreate(vmainTask1Function, "task1", 100, (void *)xQueueHandle, 1, &xTask1Handle);            // 动态创建任务
	xTaskCreate(vmainTask2Function, "task2", 100, (void *)xQueueHandle, 1, &xTask2Handle);            // 动态创建任务                                                       // 静态创建任务

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

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

static void prvSetupHardware( void )
{
	/* Start with the clocks in their expected state. */
	RCC_DeInit();

	/* Enable HSE (high speed external clock). */
	RCC_HSEConfig( RCC_HSE_ON );

	/* Wait till HSE is ready. */
	while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET )
	{
	}

	/* 2 wait states required on the flash. */
	*( ( unsigned long * ) 0x40022000 ) = 0x02;

	/* HCLK = SYSCLK */
	RCC_HCLKConfig( RCC_SYSCLK_Div1 );

	/* PCLK2 = HCLK */
	RCC_PCLK2Config( RCC_HCLK_Div1 );

	/* PCLK1 = HCLK/2 */
	RCC_PCLK1Config( RCC_HCLK_Div2 );

	/* PLLCLK = 8MHz * 9 = 72 MHz. */
	RCC_PLLConfig( RCC_PLLSource_HSE_Div1, RCC_PLLMul_9 );

	/* Enable PLL. */
	RCC_PLLCmd( ENABLE );

	/* Wait till PLL is ready. */
	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
	{
	}

	/* Select PLL as system clock source. */
	RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );

	/* Wait till PLL is used as system clock source. */
	while( RCC_GetSYSCLKSource() != 0x08 )
	{
	}

	/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
							| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );

	/* SPI2 Periph clock enable */
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );


	/* Set the Vector Table base address at 0x08000000 */
	NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );

	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

	/* Configure HCLK clock as SysTick clock source. */
	SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );
	
	serialPortInit();
}

void vmainTask1Function( void * param)
{
	volatile int i;
	int sum = 0;
	while(1) {
		for(i = 0; i < 1000000; i ++) {
			  sum += 1;
			  task1Run = 1;
	          task2Run = 0;
		      taskidleRun = 0;
		}
		xQueueSend((QueueHandle_t)param, &sum, portMAX_DELAY);
	}
}

void vmainTask2Function( void * param)
{
	int readVal;
	while(1) {
	    task1Run = 0;
	    task2Run = 1;
		taskidleRun = 0;
		xQueueReceive((QueueHandle_t)param, &readVal, portMAX_DELAY);
		printf("sum = %d\r\n", readVal);
	}
}

void vApplicationIdleHook( void )
{
	task1Run = 0;
	task2Run = 0;
	taskidleRun = 1;
}

示例代码主要的功能是动态创建一个队列,任务1进行求和,求和结束后把值放入队列中,任务2 从队列中获取任务1的求和值。在任务1计算任务没有结束时,队列中没有数据,此时任务2因为队列的阻塞访问处于阻塞态;当任务1计算结束,队列中有数据,任务2由阻塞态进入就绪态(当等待的某件事发生后将退出阻塞态,可参考文章FreeRTOS学习笔记--------任务管理)并删除已读数据,最后进入运行态。实验现象如下图所示:

使用队列实现互斥的示例代码如下:

void vmainTask3Function( void * param);
void vmainTask4Function( void * param);

QueueHandle_t initLock(void);
void getLock(QueueHandle_t handle);
void putLock(QueueHandle_t handle);

int main( void )
{
	QueueHandle_t xQueueLockHandle;

	prvSetupHardware();
	
	printf("Hello world!\r\n");
	
	xQueueLockHandle = initLock();
	
    xTaskCreate(vmainTask3Function, "task3", 100, (void *)xQueueLockHandle, 1, NULL);                 // 动态创建任务
	xTaskCreate(vmainTask4Function, "task4", 100, (void *)xQueueLockHandle, 1, NULL);            // 动态创建任务   

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

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

static void prvSetupHardware( void )
{
	/* Start with the clocks in their expected state. */
	RCC_DeInit();

	/* Enable HSE (high speed external clock). */
	RCC_HSEConfig( RCC_HSE_ON );

	/* Wait till HSE is ready. */
	while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET )
	{
	}

	/* 2 wait states required on the flash. */
	*( ( unsigned long * ) 0x40022000 ) = 0x02;

	/* HCLK = SYSCLK */
	RCC_HCLKConfig( RCC_SYSCLK_Div1 );

	/* PCLK2 = HCLK */
	RCC_PCLK2Config( RCC_HCLK_Div1 );

	/* PCLK1 = HCLK/2 */
	RCC_PCLK1Config( RCC_HCLK_Div2 );

	/* PLLCLK = 8MHz * 9 = 72 MHz. */
	RCC_PLLConfig( RCC_PLLSource_HSE_Div1, RCC_PLLMul_9 );

	/* Enable PLL. */
	RCC_PLLCmd( ENABLE );

	/* Wait till PLL is ready. */
	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
	{
	}

	/* Select PLL as system clock source. */
	RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );

	/* Wait till PLL is used as system clock source. */
	while( RCC_GetSYSCLKSource() != 0x08 )
	{
	}

	/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
							| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );

	/* SPI2 Periph clock enable */
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );


	/* Set the Vector Table base address at 0x08000000 */
	NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );

	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

	/* Configure HCLK clock as SysTick clock source. */
	SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );
	
	serialPortInit();
}

QueueHandle_t initLock(void)
{
	  QueueHandle_t xQueueHandle;
	  int val;
	  xQueueHandle = xQueueCreate(1, sizeof(int)); 
	  if(0 == xQueueHandle) {
		  printf("create queue failed!\r\n");
			return 0;
	  }
		
		xQueueSend(xQueueHandle, &val, portMAX_DELAY);
		return xQueueHandle;
}

void getLock(QueueHandle_t handle)
{
	  int val;
	  xQueueReceive(handle, &val, portMAX_DELAY);    // 读取后,队列为空
}

void putLock(QueueHandle_t handle)
{
	  int val;
	  xQueueSend(handle, &val, portMAX_DELAY);
}

void vmainTask3Function( void * param)
{
	while(1) {
		getLock((QueueHandle_t)param);
		printf("3\r\n");
		putLock((QueueHandle_t)param);
		taskYIELD();
	}
}

void vmainTask4Function( void * param)
{
	while(1) {
		getLock((QueueHandle_t)param);
		printf("4\r\n");
		// 在释放前,任务3因队列中无数据处于阻塞态
		putLock((QueueHandle_t)param);
		// 释放后,任务3处于就绪态,任务4处于运行态
		taskYIELD();
	}
}

原理与实现同步相同,**需要注意的是,队列长度为1,并且释放lock需调用taskYIELD()函数让出CPU资源。**实验现象如下,任务3和4交替使用串口。

队列集

队列集允许任务从多个队列接收数据,而无需任务依次轮询每个队列以确定哪个队列(如果有的话)包含数据。

使用队列集时,读写队列的流程如下图所示:

综上所述,向队列中写N次数据,那么队列集也相应的操作N次。另外,由此不能理解,队列集中存储的是含有数据的队列的句柄,队列集长度为所有队列长度之和。

示例代码如下所示,在使用队列集前需先在FreeRTOSConfig.h中将configUSE_QUEUE_SETS配置为1。

/*
 * Configure the clocks, GPIO and other peripherals as required by the demo.
 */
static void prvSetupHardware( void );

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

void vmainTask1Function( void * param);
void vmainTask2Function( void * param);
void vmainTask3Function( void * param);

/*-----------------------------------------------------------*/
int main( void )
{
	QueueHandle_t queueHandle1, queueHandle2;
	QueueSetHandle_t queueSetHandle;
	
	prvSetupHardware();
	
	printf("Hello world!\r\n");
	
	/*1.创建队列*/
	queueHandle1 = xQueueCreate(2, sizeof(int));
	queueHandle2 = xQueueCreate(2, sizeof(int));
	
	/*2.创建队列集,队列集长度等于所有队列长度之和*/
	queueSetHandle = xQueueCreateSet(4);
	
	/*3.将队列添加进队列集*/
	xQueueAddToSet(queueHandle1, queueSetHandle);
	xQueueAddToSet(queueHandle2, queueSetHandle);
	
	xTaskCreate(vmainTask1Function, "task1", 100, (void *)queueHandle1, 1, NULL);            // 动态创建任务
	xTaskCreate(vmainTask2Function, "task2", 100, (void *)queueHandle2, 1, NULL);            // 动态创建任务
  xTaskCreate(vmainTask3Function, "task3", 100, (void *)queueSetHandle, 1, NULL);            // 动态创建任务

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

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

static void prvSetupHardware( void )
{
	/* Start with the clocks in their expected state. */
	RCC_DeInit();

	/* Enable HSE (high speed external clock). */
	RCC_HSEConfig( RCC_HSE_ON );

	/* Wait till HSE is ready. */
	while( RCC_GetFlagStatus( RCC_FLAG_HSERDY ) == RESET )
	{
	}

	/* 2 wait states required on the flash. */
	*( ( unsigned long * ) 0x40022000 ) = 0x02;

	/* HCLK = SYSCLK */
	RCC_HCLKConfig( RCC_SYSCLK_Div1 );

	/* PCLK2 = HCLK */
	RCC_PCLK2Config( RCC_HCLK_Div1 );

	/* PCLK1 = HCLK/2 */
	RCC_PCLK1Config( RCC_HCLK_Div2 );

	/* PLLCLK = 8MHz * 9 = 72 MHz. */
	RCC_PLLConfig( RCC_PLLSource_HSE_Div1, RCC_PLLMul_9 );

	/* Enable PLL. */
	RCC_PLLCmd( ENABLE );

	/* Wait till PLL is ready. */
	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
	{
	}

	/* Select PLL as system clock source. */
	RCC_SYSCLKConfig( RCC_SYSCLKSource_PLLCLK );

	/* Wait till PLL is used as system clock source. */
	while( RCC_GetSYSCLKSource() != 0x08 )
	{
	}

	/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
							| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE );

	/* SPI2 Periph clock enable */
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );


	/* Set the Vector Table base address at 0x08000000 */
	NVIC_SetVectorTable( NVIC_VectTab_FLASH, 0x0 );

	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

	/* Configure HCLK clock as SysTick clock source. */
	SysTick_CLKSourceConfig( SysTick_CLKSource_HCLK );
	


**先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前在阿里**

**深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/2740b99a905338a9b86f448b1123a483.png)
![img](https://img-blog.csdnimg.cn/img_convert/f128b3624dcc5dacb1ea1e764e940af4.png)
![img](https://img-blog.csdnimg.cn/img_convert/2a360d1b430db1ab94bfab1614f81ccb.png)
![img](https://img-blog.csdnimg.cn/img_convert/e256b6803a800879c327c26ad9a603fe.png)
![img](https://img-blog.csdnimg.cn/img_convert/a2baed234b825ed28f7a66bc3eafd701.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

节跳动等大厂,目前在阿里**

**深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
[外链图片转存中...(img-VzIwcEFN-1715132430358)]
[外链图片转存中...(img-h3v6Tn8j-1715132430359)]
[外链图片转存中...(img-oZMhXNvL-1715132430360)]
[外链图片转存中...(img-qAIu5i7b-1715132430361)]
[外链图片转存中...(img-11wCKiVu-1715132430361)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值