STM32 | FreeRTOS 消息隊列

01??

一、概述

隊列又稱消息隊列,是一種常用于任務間通信的數據結構,隊列可以在任務與任務間、中斷和任務間傳遞信息,實現了任務接收來自其他任務或中斷的不固定長度的消息,任務能夠從隊列里面讀取消息,當隊列中的消息是空時,讀取消息的任務將被阻塞,用戶還可以指定阻塞的任務時間?xTicksToWait,在這段時間中,如果隊列為空,該任務將保持阻塞狀態以等待隊列數據有效。

當隊列中有新消息時,被阻塞的任務會被喚醒并處理新消息;當等待的時間超過了指定的阻塞時間,即使隊列中尚無有效數據,任務也會自動從阻塞態轉為就緒態

消息隊列是一種異步的通信方式。通過消息隊列服務,任務或中斷服務例程可以將一條或多條消息放入消息隊列中。同樣,一個或多個任務可以從消息隊列中獲得消息。當有多個消息發送到消息隊列時,通常是將先進入消息隊列的消息先傳給任務,也就是說,任務先得到的是最先進入消息隊列的消息,即先進先出原則(FIFO),但是也支持后進先出原則(LIFO)。

特性

FreeRTOS 中使用隊列數據結構實現任務異步通信工作,具有如下特性:?

  • LIFO)。?

應用場景

消息隊列可以應用于發送不定長消息的場合,包括任務與任務間的消息交換,隊列是?FreeRTOS 主要的任務間通訊方式,可以在任務與任務間、中斷和任務間傳送信息,發送到隊列的消息是通過拷貝方式實現的,這意味著隊列存儲的數據是原數據,而不是原數據的引用。

02??

二、消息隊列的運作機制

? ? 創建消息隊列時?FreeRTOS 會先給消息隊列分配一塊內存空間,這塊內存的大小等于消息隊列控制塊大小加上(單個消息空間大小與消息隊列長度的乘積),接著再初始化消息隊列,此時消息隊列為空。FreeRTOS的消息隊列控制塊由多個元素組成,當消息隊列被 創建時,系統會為控制塊分配對應的內存空間,用于保存消息隊列的一些信息如消息的存 儲位置,頭指針 pcHead、尾指針 pcTail、消息大小uxItemSize以及隊列長度uxLength等。同時每個消息隊列都與消息空間在同一段連續的內存空間中,在創建成功的時候,這些內存就被占用了,只有刪除了消息隊列的時候,這段內存才會被釋放掉,創建成功的時候就已經分配好每個消息空間與消息隊列的容量,無法更改,每個消息空間可以存放不大于消息大小uxItemSize的任意類型的數據,所有消息隊列中的消息空間總數即是消息隊列的長度,這個長度可在消息隊列創建時指定。

? ? 任務或者中斷服務程序都可以給消息隊列發送消息,當發送消息時,如果隊列未滿或者允許覆蓋入隊,FreeRTOS 會將消息拷貝到消息隊列隊尾,否則,會根據用戶指定的阻塞 超時時間進行阻塞,在這段時間中,如果隊列一直不允許入隊,該任務將保持阻塞狀態以等待隊列允許入隊。當其它任務從其等待的隊列中讀取入了數據(隊列未滿),該任務將 自動由阻塞態轉移為就緒態。當等待的時間超過了指定的阻塞時間,即使隊列中還不允許 入隊,任務也會自動從阻塞態轉移為就緒態,此時發送消息的任務或者中斷程序會收到一個錯誤碼 errQUEUE_FULL。

發送緊急消息的過程與發送消息幾乎一樣,唯一的不同是,當發送緊急消息時,發送的位置是消息隊列隊頭而非隊尾,這樣,接收者就能夠優先接收到緊急消息,從而及時進行消息處理。

? ? 當某個任務試圖讀一個隊列時,其可以指定一個阻塞超時時間。在這段時間中,如果隊列為空,該任務將保持阻塞狀態以等待隊列數據有效。當其它任務或中斷服務程序往其等待的隊列中寫入了數據,該任務將自動由阻塞態轉移為就緒態。當等待的時間超過了指定的阻塞時間,即使隊列中尚無有效數據,任務也會自動從阻塞態轉移為就緒態。

? ? 當消息隊列不再被使用時,應該刪除它以釋放系統資源,一旦操作完成,消息隊列將被永久性的刪除。

03??

1.消息隊列創建函數?

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength,UBaseType_t uxItemSize);

功能描述:用于創建一個新的隊列。

參數:

返回值:

成功-如果創建成功則返回一個隊列句柄,用于訪問創建的隊列;

失敗-如果創建不成功則返回NULL,可能原因是創建隊列需要的 RAM 無法分配成功。

04??

2.消息隊列靜態創建函數

QueueHandle_t xQueueCreateStatic(UBaseType_t uxQueueLength,UBaseType_t uxItemSize,uint8_t *pucQueueStorageBuffer,StaticQueue_t *pxQueueBuffer );

功能描述:用于創建一個新的隊列。

參數:

  1. uint8_t 類型的數組,數組的大小至少有uxQueueLength* uxItemSize 個字節。當 uxItemSize 為 0 時,pucQueueStorageBuffer 可以為 NULL。
  1. StaticQueue_t 類型的變量,該變量用于存儲隊列的數據結構。

返回值:

成功-如果創建成功則返回一個隊列句柄,用于訪問創建的隊列;

失敗-如果創建不成功則返回NULL,可能原因是創建隊列需要的 RAM 無法分配成功。

05??

3.用于向隊列尾部發送一個隊列消息

BaseType_t xQueueSend(QueueHandle_t xQueue,const void * pvItemToQueue,TickType_t xTicksToWait);

參數說明:

  1. xTicksToWait?被設置成0,函數立刻返回。超時時間的單位為系統節拍周期,常量portTICK_PERIOD_MS?用于輔助計算真實的時間,單位為ms。如果INCLUDE_vTaskSuspend?設置成1,并且指定延時為portMAX_DELAY?將導致任務掛起(沒有超時)。

返回值:

消息發送成功成功返回pdTRUE,否則返回errQUEUE_FULL。

06??

4.在中斷服務程序中用于向隊列尾部發送一個消息

BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);

參數說明:

  1. 隊列句柄。
  2. 指針,指向要發送到隊列尾部的消息。
  3. 如果入隊導致一個任務解鎖,并且解鎖的任務優先級高于當前被中斷的任務,則將*pxHigherPriorityTaskWoken設置成pdTRUE,然后在中斷退出前需要進行一次上下文切換,去執行被喚醒的優先級更高的任務。從FreeRTOS V7.3.0?起,pxHigherPriorityTaskWoken?作為一個可選參數,可以設置為NULL。

返回值:

消息發送成功成功返回pdTRUE,否則返回errQUEUE_FULL。

5.向隊列隊首發送一個消息

BaseType_t xQueueSendToFront( QueueHandle_t xQueue,const void * pvItemToQueue,TickType_t xTicksToWait );

參數說明:

  1. 被設置成 0,函數立刻返回。超時時間的單位為系統節拍周期,常量 portTICK_PERIOD_MS 用于輔助計算真實的時間,單位為 ms。如果 INCLUDE_vTaskSuspend 設置成 1,并且指定延時為 portMAX_DELAY 將導致任務無限阻塞(沒有超時)。

返回值:

消息發送成功成功返回pdTRUE,否則返回errQUEUE_FULL。

6.在中斷服務程序中向消息隊列隊首發送一個消息

BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken);

參數說明:

  1. 隊列句柄。
  2. 指針,指向要發送到隊首的消息。
  3. 如果入隊導致一個任務解鎖,并且解鎖的任務優先級高于當前被中斷的任務,則將*pxHigherPriorityTaskWoken設置成pdTRUE,然后在中斷退出前需要進行一次上下文切換,去執行被喚醒的優先級更高的任務。從FreeRTOS V7.3.0?起,pxHigherPriorityTaskWoken?作為一個可選參數,可以設置為NULL。

返回值:

消息發送成功成功返回pdTRUE,否則返回errQUEUE_FULL。

7.從一個隊列中接收消息,并把接收的消息從隊列中刪除

BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);

參數說明:

  1. 地址。
  2. 0,函數立刻返 回。超時時間的單位為系統節拍周期,常量 portTICK_PERIOD_MS 用 于輔助計算真實的時間,單位為 ms。如果 INCLUDE_vTaskSuspend 設 置成 1,并且指定延時為 portMAX_DELAY 將導致任務無限阻塞(沒有超時)。

返回值:

隊列項接收成功返回?pdTRUE,否則返回 pdFALSE。

若接收完消息,不想刪除,可以使用xQueuePeek函數。

8.在中斷中從一個隊列中接收消息,并從隊列中刪除該消息

BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, void *pvBuffer, BaseType_t *pxHigherPriorityTaskWoken);

參數說明:

  1. 在該隊列上。如果 xQueueReceiveFromISR()到賬了一個任務解鎖了則將 *pxHigherPriorityTaskWoken設置為pdTRUE ,否則 *pxHigherPriorityTaskWoken的值將不變。從 FreeRTOS V7.3.0 起,pxHigherPriorityTaskWoken 作為一個可選參數,可以設置為NULL。

返回值:

隊列項接收成功返回?pdTRUE,否則返回 pdFALSE。

若接收完消息,不想刪除,可以使用xQueuePeekFromISR函數。

07??

四、消息隊列使用注意事項

在使用?FreeRTOS 提供的消息隊列函數的時候,需要了解以下幾點:?

1. 使用 xQueueSend()、xQueueSendFromISR()、xQueueReceive()等這些函數之前應先 創建需消息隊列,并根據隊列句柄進行操作。?

2. 隊列讀取采用的是先進先出(FIFO)模式,會先讀取先存儲在隊列中的數據。當 然也 FreeRTOS 也支持后進先出(LIFO)模式,那么讀取的時候就會讀取到后進 隊列的數據。?

3. 在獲取隊列中的消息時候,我們必須要定義一個存儲讀取數據的地方,并且該數 據區域大小不小于消息大小,否則,很可能引發地址非法的錯誤。?

4. 無論是發送或者是接收消息都是以拷貝的方式進行,如果消息過于龐大,可以將消息的地址作為消息進行發送、接收。

5. 隊列是具有自己獨立權限的內核對象,并不屬于任何任務。所有任務都可以向同一隊列寫入和讀出。一個隊列由多任務或中斷寫入是經常的事,但由多個任務讀出倒是用的比較少。

6、在中斷使用消息隊列發送與接收時注意將搶占優先級設置大于等于5,官方庫存函數說明如下

/* The highest interrupt priority that can be used by any interrupt serviceroutine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALLINTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHERPRIORITY THAN THIS! (higher priorities are lower numeric values. */#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY?5

08??

五、示例代碼

5.1 任務之間消息傳遞

1.freertos.cvoid MX_FREERTOS_Init(void) {/* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... *//* 創建Test_Queue */Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,/* 消息隊列的長度 */(UBaseType_t ) QUEUE_SIZE);/* 消息的大小 */if(NULL == Test_Queue)printf("創建Test_Queue消息隊列失敗!\r\n");/* USER CODE END RTOS_QUEUES *//* Create the thread(s) *//* definition and creation of defaultTask */// osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);//defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);/* USER CODE BEGIN RTOS_THREADS *//* 創建app_task2任務 */app_task1_handle=xTaskCreateStatic((TaskFunction_t )app_task1, ?/* 任務入口函數 */(const char* ? ?)"app_task1",/* 任務名字 */(uint16_t ? ? ? )512, ?/* 任務棧大小 */(void* ? ? ? ? ?)NULL,/* 任務入口函數參數 */(UBaseType_t ? ?)4,?/* 任務的優先級 */(StackType_t* ? )app_task1_stack,//任務堆棧(StaticTask_t* ?)&app_task1_buffer);/* 任務控制塊指針 */?app_task2_handle=xTaskCreateStatic((TaskFunction_t )app_task2, ?/* 任務入口函數 */(const char* ? ?)"app_task2",/* 任務名字 */(uint16_t ? ? ? )512, ?/* 任務棧大小 */(void* ? ? ? ? ?)NULL,/* 任務入口函數參數 */(UBaseType_t ? ?)5,?/* 任務的優先級 */(StackType_t* ? )app_task2_stack,//任務堆棧(StaticTask_t* ?)&app_task2_buffer);/* 任務控制塊指針 */???/* add threads, ... *//* USER CODE END RTOS_THREADS */}/* USER CODE BEGIN Header_StartDefaultTask *//*** @brief Function implementing the defaultTask thread.* @param argument: Not used?* @retval None*//* USER CODE END Header_StartDefaultTask */void StartDefaultTask(void const * argument){/* USER CODE BEGIN StartDefaultTask *//* Infinite loop */for(;;){osDelay(1000);}/* USER CODE END StartDefaultTask */}/* Private application code --------------------------------------------------*//* USER CODE BEGIN Application */static void app_task1(void* pvParameters){BaseType_t xReturn=pdFALSE;uint32_t txd = 1;for(;;){xReturn = xQueueSend(?Test_Queue,?/* 消息隊列的句柄 */&txd,/* 發送的消息內容 */0 ); ? ? ? ?/* 等待時間 0 */if(pdPASS == xReturn)printf("[app_task1]消息txd發送成功!\r\n");elseprintf("[app_task2]消息txd發送失敗!\r\n");txd++;vTaskDelay(1000);}}?static void app_task2(void* pvParameters){BaseType_t xReturn=pdFALSE;uint32_t rxd;/* 定義一個接收消息的變量 */for(;;){xReturn = xQueueReceive( Test_Queue, ? ? /* 消息隊列的句柄 */&rxd, ? ? ?/* 發送的消息內容 */portMAX_DELAY); /* 等待時間一直等 */if(pdTRUE == xReturn)printf("[app_task2]本次接收到的數據是%x\r\n",rxd);elseprintf("[app_task2]數據接收出錯,錯誤代碼0x%lx\n",xReturn); ?}}?

2. 演示

09??

5.2 中斷向任務發送消息

1.freertos.cstatic void app_task1(void* pvParameters){BaseType_t xReturn=pdFALSE;char buf[QUEUE_SIZE]={0};uint32_t task_cnt=0;for(;;){task_cnt++;sprintf(buf,"app_task1 have run %d times",task_cnt);xReturn = xQueueSend(?Test_Queue, /*?消息隊列的句柄?*/buf,/*?發送的消息內容?*/0 ); ? ? ? ?/*?等待時間?0 */if(pdPASS == xReturn)printf("[app_task1]消息txd發送成功!\r\n");elseprintf("[app_task2]消息txd發送失敗!\r\n");vTaskDelay(3000);}}?static void app_task2(void* pvParameters){BaseType_t xReturn=pdFALSE;uint8_t buf[QUEUE_SIZE]={0};/*?定義一個接收消息的變量?*/for(;;){xReturn = xQueueReceive(?Test_Queue, ? ? /*?消息隊列的句柄?*/buf, ? ? ?/*?發送的消息內容?*/portMAX_DELAY); /*?等待時間一直等?*/if(pdTRUE == xReturn)printf("[app_task2]本次接收到的數據是%s\r\n",buf);elseprintf("[app_task2]數據接收出錯,錯誤代碼0x%lx\n",xReturn); ?memset(buf,0,sizeof buf);}}?2.usart.cstatic volatile uint8_t?g_usart1_recv_buf[64]={0};static volatile uint32_t?g_usart1_recv_cnt = 0;extern QueueHandle_t Test_Queue;?void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){uint32_t ulReturn;/*?進入臨界段,臨界段可以嵌套?*/ulReturn = taskENTER_CRITICAL_FROM_ISR();if(huart->Instance == USART1)//?判斷是由哪個串口觸發的中斷{g_usart1_recv_buf[g_usart1_recv_cnt]=hal_uart_rx_data;//記錄多少個數據g_usart1_recv_cnt++;//檢測到'#'符或接收的數據滿的時候則發送數據if(hal_uart_rx_data=='#' || g_usart1_recv_cnt>=(sizeof g_usart1_recv_buf)){xQueueSendFromISR(Test_Queue,(void *)g_usart1_recv_buf,NULL);g_usart1_recv_cnt=0;}//?重新使能串口1接收中斷HAL_UART_Receive_IT(huart,&hal_uart_rx_data,1);}/*?退出臨界段?*/taskEXIT_CRITICAL_FROM_ISR( ulReturn );}

3. 演示

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80361.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80361.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80361.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java 安全漏洞掃描工具:如何快速發現和修復潛在問題?

Java 安全漏洞掃描工具:如何快速發現和修復潛在問題? 在當今的軟件開發領域,Java 作為一種廣泛使用的編程語言,其應用的規模和復雜度不斷攀升。然而,隨著應用的拓展,Java 應用面臨的潛在安全漏洞風險也日益…

Python繪制克利夫蘭點圖:從入門到實戰

Python繪制克利夫蘭點圖:從入門到實戰 引言 克利夫蘭點圖(Cleveland Dot Plot)是一種強大的數據可視化工具,由統計學家William Cleveland在1984年提出。這種圖表特別適合展示多個類別的數值比較,比傳統的條形圖更直觀…

LVGL- Calendar 日歷控件

1 日歷控件 1.1 日歷背景 lv_calendar 是 LVGL(Light and Versatile Graphics Library)提供的標準 GUI 控件之一,用于顯示日歷視圖。它支持用戶查看某年某月的完整日歷,還可以實現點擊日期、標記日期、導航月份等操作。這個控件…

多指標組合策略

該策略(MultiConditionStrategy)是一種基于多種技術指標和市場條件的交易策略。它通過綜合考慮多個條件來生成交易信號,從而決定買入或賣出的時機。 以下是對該策略的詳細分析: 交易邏輯思路 1. 條件1:星期幾和價格變化判斷 - 該條件根據當前日期是星期幾以及價格的變化…

BC 范式與 4NF

接下來我們詳細解釋 BC 范式(Boyce-Codd范式,簡稱 BCNF),并通過具體例子說明其定義和應用。 一、BC范式的定義 BC范式(Boyce-Codd范式,BCNF)是數據庫規范化理論中的一種范式,它比第…

基于 CSS Grid 的網頁,拆解頁面整體布局結構

通過以下示例拆解網頁整體布局結構&#xff1a; 一、基礎結構&#xff08;HTML骨架&#xff09; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"…

采購流程規范化如何實現?日事清流程自動化助力需求、采購、財務高效協作

采購審批流程全靠人推進&#xff0c;內耗嚴重&#xff0c;效率低下&#xff1f; 花重金上了OA&#xff0c;結果功能有局限、不靈活&#xff1f; 問題出在哪里&#xff1f;是我們的要求太多、太苛刻嗎&#xff1f;NO&#xff01; 流程名稱&#xff1a; 采購審批管理 流程功能…

全棧項目搭建指南:Nuxt.js + Node.js + MongoDB

全棧項目搭建指南&#xff1a;Nuxt.js Node.js MongoDB 一、項目概述 我們將構建一個完整的全棧應用&#xff0c;包含&#xff1a; 前端&#xff1a;Nuxt.js (SSR渲染)后端&#xff1a;Node.js (Express/Koa框架)數據庫&#xff1a;MongoDB后臺管理系統&#xff1a;集成在同…

NVMe簡介6之PCIe事務層

PCIe的事務層連接了PCIe設備核心與PCIe鏈路&#xff0c;這里主要基于PCIe事務層進行分析。事務層采用TLP傳輸事務&#xff0c;完整的TLP由TLPPrefix、TLP頭、Payload和TLP Digest組成。TLP頭是TLP中最關鍵的部分&#xff0c;一般由三個或四個雙字的長度&#xff0c;其格式定義如…

Python異常模塊和包

異常 當檢測到一個錯誤時&#xff0c;Python解釋器就無法繼續執行了&#xff0c;反而出現了一些錯誤的提示&#xff0c;這就是所謂的“異常”, 也就是我們常說的BUG 例如&#xff1a;以r方式打開一個不存在的文件。 f open(‘python1.txt’,‘r’,encoding‘utf-8’) 當我們…

匯編:循環程序設計

一、 實驗要求 熟練掌握循環程序設計的基本方法熟練掌握單片機外部存儲空間的訪問方法 二、 實驗設計 1.整體思路 先初始化一些寄存器和數據存儲位置&#xff0c;然后調用兩個子程序Procedure1和Procedure2&#xff0c;分別從SRC復制數據到DEST&#xff0c;一個從開頭到末尾&…

典籍知識問答模塊AI問答bug修改

一、修改流式數據處理問題 1.問題描述&#xff1a;由于傳來的數據形式如下&#xff1a; event:START data:350 data:< data:t data:h data:i data:n data:k data:> data: data: data: data: data:嗯 data:&#xff0c; 導致需要修改獲取正常的當前信息id并更…

【金倉數據庫征文】- 金融HTAP實戰:KingbaseES實時風控與毫秒級分析一體化架構

文章目錄 引言&#xff1a;金融數字化轉型的HTAP引擎革命一、HTAP架構設計與資源隔離策略1.1 混合負載物理隔離架構1.1.1 行列存儲分區策略1.1.2 四級資源隔離機制 二、實時流處理與增量同步優化2.1 分鐘級新鮮度保障2.1.1 WAL日志增量同步2.1.2 流計算優化 2.2 物化視圖實時刷…

季報中的FPGA行業:U型反轉,春江水暖

上周Lattice,AMD兩大廠商相繼發布2025 Q1季報,盡管恢復速度各異,但同時傳遞出FPGA行業整體回暖的復蘇信號。 5月5日,Lattice交出了“勉強及格”的答卷,報告季度營收1億2000萬,與華爾街的預期基本相符。 對于這家聚焦在中小規模器件的領先廠商而言,按照其CEO的預期,長…

使用 javap 深入理解 Java 字節碼

引言 Java 是一種廣泛使用的高級編程語言,其獨特之處在于編譯后的代碼不是直接的機器碼,而是一種稱為字節碼的中間表示形式。字節碼存儲在 .class 文件中,由 Java 虛擬機 (JVM) 解釋或即時編譯為特定平臺的機器碼。這種設計賦予了 Java 平臺無關性,即“一次編寫,到處運行…

LeetCode_sql刷題(3482.分析組織層級)

題目描述&#xff1a;3482. 分析組織層級 - 力扣&#xff08;LeetCode&#xff09; 表&#xff1a;Employees ------------------------- | Column Name | Type | ------------------------- | employee_id | int | | employee_name | varchar | | manager_id …

工業場景輪式巡檢機器人純視覺識別導航的優勢剖析與前景展望

一、引言 1.1 研究背景與意義 在工業 4.0 的大背景下&#xff0c;工業生產的智能化、自動化水平不斷提高&#xff0c;對工業場景的巡檢工作提出了更高的要求。傳統的人工巡檢方式不僅效率低下、成本高昂&#xff0c;而且容易受到人為因素的影響&#xff0c;難以滿足現代工業生…

《棒球萬事通》球類運動有哪些項目·棒球1號位

以棒球運動為例&#xff0c;棒球運動涉及多個核心項目和比賽形式&#xff0c;以下為主要分類&#xff1a; 一、比賽環節 投球&#xff08;Pitching&#xff09; 防守方投手向擊球員投球&#xff0c;目標是讓對方難以擊中或制造出局。 擊球&#xff08;Batting&#xff09; …

第五項修煉:打造學習型組織

最近一直接到的需求&#xff0c;都是公司董事長或總經理都特別推崇《第五項修煉&#xff1a;打造學習型組織》的內容&#xff0c;讓各個層級的管理者都持續學習、應用、實踐。我不禁開始反思&#xff0c;這背后到底隱藏著什么原因&#xff1f; 隨著商業環境的變化和復雜性的增加…

國內AWS CloudFront與S3私有桶集成指南:安全訪問靜態內容

在現代web應用架構中,將靜態內容存儲在Amazon S3中并通過CloudFront分發是一種常見且高效的做法。本指南將詳細介紹如何創建私有S3桶,配置CloudFront分配,并使用Origin Access Identity (OAI)來確保安全訪問。 步驟1:創建S3桶 首先,我們需要創建一個名為"b-static&…