FreeRTOS高階篇5---FreeRTOS佇列分析
- FreeRTOS提供了多種任務間通訊方式,包括:
- 任務通知(版本V8.2以及以上版本)
- 佇列
- 二進位制訊號量
- 計數訊號量
- 互斥量
- 遞迴互斥量
- 其中,二進位制訊號量、計數訊號量、互斥量和遞迴互斥量都是使用佇列來實現的,因此掌握佇列的執行機制,是很有必要的。
佇列是FreeRTOS主要的任務間通訊方式。可以在任務與任務間、中斷和任務間傳送資訊。傳送到佇列的訊息是通過拷貝實現的,這意味著佇列儲存的資料是原資料,而不是原資料的引用。先看一下佇列的資料結構: -
typedef struct QueueDefinition
-
{
-
int8_t *pcHead; /* 指向佇列儲存區起始位置,即第一個佇列項 */
-
int8_t *pcTail; /* 指向佇列儲存區結束後的下一個位元組 */
-
int8_t *pcWriteTo; /* 指向下佇列儲存區的下一個空閒位置 */
-
union /* 使用聯合體用來確保兩個互斥的結構體成員不會同時出現 */
-
{
-
int8_t *pcReadFrom; /* 當結構體用於佇列時,這個欄位指向出隊專案中的最後一個. */
-
UBaseType_t uxRecursiveCallCount;/* 當結構體用於互斥量時,用作計數器,儲存遞迴互斥量被"獲取"的次數. */
-
} u;
-
List_t xTasksWaitingToSend; /* 因為等待入隊而阻塞的任務列表,按照優先順序順序儲存 */
-
List_t xTasksWaitingToReceive; /* 因為等待佇列項而阻塞的任務列表,按照優先順序順序儲存 */
-
volatile UBaseType_t uxMessagesWaiting;/*< 當前佇列的佇列項數目 */
-
UBaseType_t uxLength; /* 佇列項的數目 */
-
UBaseType_t uxItemSize; /* 每個佇列項的大小 */
-
volatile BaseType_t xRxLock; /* 佇列上鎖後,儲存從佇列收到的列表項數目,如果佇列沒有上鎖,設定為queueUNLOCKED */
-
volatile BaseType_t xTxLock; /* 佇列上鎖後,儲存傳送到佇列的列表項數目,如果佇列沒有上鎖,設定為queueUNLOCKED */
-
#if ( configUSE_QUEUE_SETS == 1 )
-
struct QueueDefinition *pxQueueSetContainer;
-
#endif
-
#if ( configUSE_TRACE_FACILITY == 1 )
-
UBaseType_t uxQueueNumber;
-
uint8_t ucQueueType;
-
#endif
-
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
-
uint8_t ucStaticAllocationFlags;
-
#endif
-
} xQUEUE;
-
typedef xQUEUE Queue_t;
- 下面的所有API函式都是圍繞這個資料結構展開,因此資料結構的每個成員都需要了解。如果你是第一次看這篇文章,即使有註釋,可能你對結構體的某些成員還是不理解,不要著急,這是正常的。後面介紹API函式的時候,會一一使用這些成員,結合著具體例項,會很容理解的,你需要做的,是要反覆翻到這裡檢視。
1.佇列建立函式
在《FreeRTOS系列第18篇---FreeRTOS佇列API函式》一文中,我們介紹了建立佇列API函式xQueueCreate(),但其實這是一個巨集,只是定義的像函式而已。真正被執行的函式是xQueueGenericCreate(),我們稱這個函式為通用佇列建立函式。 我們來分析一下xQueueGenericCreate()函式,函式原型為: -
QueueHandle_t xQueueGenericCreate
-
(
-
const UBaseType_t uxQueueLength,
-
const UBaseType_t uxItemSize,
-
uint8_t *pucQueueStorage,
-
StaticQueue_t *pxStaticQueue,
-
const uint8_t ucQueueType
-
)
- uxQueueLength:佇列項數目
- uxItemSize:每個佇列項的大小
- pucQueueStorage:使用靜態分配佇列時才使用,指向定義佇列儲存空間,如果使用動態分配佇列空間(預設),向這個引數傳遞NULL。
- pxStaticQueue:使用靜態分配佇列時才使用,指向佇列控制結構體,如果使用動態分配佇列空間(預設),向這個引數傳遞NULL。
- ucQueueType:型別。可能的值為:
- queueQUEUE_TYPE_BASE:表示佇列
- queueQUEUE_TYPE_SET:表示佇列集合
- queueQUEUE_TYPE_MUTEX:表示互斥量
- queueQUEUE_TYPE_COUNTING_SEMAPHORE:表示計數訊號量
- queueQUEUE_TYPE_BINARY_SEMAPHORE:表示二進位制訊號量
- queueQUEUE_TYPE_RECURSIVE_MUTEX :表示遞迴互斥量
- 然而,等下我們看原始碼,就會看到,在xQueueGenericCreate()函式中,引數ucQueueType只是用來視覺化跟蹤除錯用。
xQueueGenericCreate()函式的原始碼如下所示: -
QueueHandle_t xQueueGenericCreate(
-
const UBaseType_t uxQueueLength,
-
const UBaseType_t uxItemSize,
-
uint8_t *pucQueueStorage,
-
StaticQueue_t *pxStaticQueue,
-
const uint8_t ucQueueType )
-
{
-
Queue_t *pxNewQueue;
-
/* 如果使能視覺化跟蹤除錯,這裡用來消除編譯器警告. */
-
( void ) ucQueueType;
-
/*分配佇列結構體和佇列項儲存空間.可以靜態也可以動態分配,取決於引數值,FreeRTOS預設採取動態分配 */
-
pxNewQueue = prvAllocateQueueMemory( uxQueueLength, uxItemSize, &pucQueueStorage, pxStaticQueue );
-
if( pxNewQueue != NULL )
-
{
-
if( uxItemSize == ( UBaseType_t ) 0 )
-
{
-
/* 沒有為佇列項儲存分配記憶體,但是pcHead指標不能設定為NULL,因為佇列用作互斥量時,pcHead要設定成NULL.這裡只是將pcHead指向一個已知的區域 */
-
pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
-
}
-
else
-
{
-
/* 指向佇列項儲存區域*/
-
pxNewQueue->pcHead = ( int8_t * ) pucQueueStorage;
-
}
-
/* 初始化佇列結構體成員*/
-
pxNewQueue->uxLength = uxQueueLength;
-
pxNewQueue->uxItemSize = uxItemSize;
-
( void ) xQueueGenericReset( pxNewQueue, pdTRUE );
-
#if ( configUSE_TRACE_FACILITY == 1 )
-
{
-
pxNewQueue->ucQueueType = ucQueueType;
-
}
-
#endif /* configUSE_TRACE_FACILITY */
-
traceQUEUE_CREATE( pxNewQueue );
-
}
-
return ( QueueHandle_t ) pxNewQueue;
-
}
- 我們以預設的動態分配佇列儲存空間方式講述一下佇列建立過程。首先呼叫函式prvAllocateQueueMemory分配佇列結構體和佇列項儲存空間,結構體和佇列項在儲存空間上是連續的,如圖1-1所示。
圖1-1:為佇列分配的記憶體
如果佇列記憶體申請成功,接下來會初始化佇列結構體成員,先是pcHead成員,然後是uxLength和uxItemSize成員,最後呼叫函式xQueueGenericReset()初始化剩下的結構體成員。
假設我們申請了3個佇列項,每個佇列項佔用4位元組儲存空間(即uxLength=3、uxItemSize=4),則經過初始化後的佇列記憶體如圖1-2所示。(這個圖形象的描述了佇列結構體的大部分成員的作用)。圖1-2:初始化後的佇列項記憶體
2.入隊
佇列項入隊也稱為投遞(Send),分為帶中斷保護的入隊操作和不帶中斷保護的入隊操作。每種情況下又分為從佇列尾部入隊和從佇列首部入隊兩種操作,從佇列尾部入隊還有一種特殊情況,覆蓋式入隊,即佇列滿後自動覆蓋最舊的佇列項。如表2-1所示。表2-1:入隊API介面列表
2.1 xQueueGenericSend()
這個函式用於入隊操作,絕不可以用在中斷服務程式中。根據引數的不同,可以從佇列尾入隊、從佇列首入隊和覆蓋式入隊。覆蓋式入隊用於只有一個佇列項的場合,入隊時如果佇列已滿,則將之前的佇列項覆蓋掉。函式原型為: -
BaseType_t xQueueGenericSend
-
(
-
QueueHandle_t xQueue,
-
const void * const pvItemToQueue,
-
TickType_t xTicksToWait,
-
const BaseType_t xCopyPosition
-
)
- xQueue:佇列控制代碼
- pvItemToQueue:指標,指向要入隊的專案
- xTicksToWait:如果佇列滿,等待佇列空閒的最大時間,如果佇列滿並且xTicksToWait被設定成0,函式立刻返回。時間單位為系統節拍時鐘週期,巨集portTICK_PERIOD_MS可以用來輔助計算真實延時值。如果INCLUDE_vTaskSuspend設定成1,並且指定延時為portMAX_DELAY將引起任務無限阻塞(沒有超時)。
- xCopyPosition:入隊位置,可以選擇從佇列尾入隊、從佇列首入隊和覆蓋式入隊。
- 這個函式為了獲得最高效率而放寬了編碼標準:有多個返回點。因此如果純粹以文字方式來講解,我覺得很難達到好的效果,所以我首先給出整理後的原始碼(去除除錯和佇列集合有關程式碼),然後畫出流程圖,對函式的關鍵點做重點描述。
整理後的原始碼: -
BaseType_t xQueueGenericSend(
-
QueueHandle_t xQueue,
-
const void * const pvItemToQueue,
-
TickType_t xTicksToWait,
-
const BaseType_t xCopyPosition )
-
{
-
BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
-
TimeOut_t xTimeOut;
-
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
-
for( ;; )
-
{
-
taskENTER_CRITICAL();
-
{
-
/* 佇列還有空閒?正在執行的任務一定要比等待訪問佇列的任務優先順序高.如果使用覆蓋式入隊,則不需要關注佇列是否滿*/
-
if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
-
{
-
/*完成資料拷貝工作,分為從佇列尾入隊,從佇列首入隊和覆蓋式入隊*/
-
xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
-
/* 如果有任務在此等待佇列資料到來,則將該任務解除阻塞*/
-
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-
{
-
/*有任務因等待出隊而阻塞,則將任務從佇列等待接收列表中刪除,然後加入到就緒列表*/
-
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-
{
-
/* 解除阻塞的任務有更高的優先順序,則當前任務要讓出CPU,因此觸發一個上下文切換.又因為現在還在臨界區,要等退出臨界區後,才會執行上下文切換.*/
-
queueYIELD_IF_USING_PREEMPTION();
-
}
-
}
-
else if( xYieldRequired != pdFALSE )
-
{
-
/* 這個分支處理特殊情況*/
-
queueYIELD_IF_USING_PREEMPTION();
-
}
-
taskEXIT_CRITICAL();
-
return pdPASS;
-
}
-
else
-
{
-
if( xTicksToWait == ( TickType_t ) 0 )
-
{
-
/* 如果佇列滿並且沒有設定超時,則直接退出 */
-
taskEXIT_CRITICAL();
-
/* 返回佇列滿錯誤碼 */
-
return errQUEUE_FULL;
-
}
-
else if( xEntryTimeSet == pdFALSE )
-
{
-
/* 佇列滿並且規定了阻塞時間,因此需要配置超時結構體物件 */
-
vTaskSetTimeOutState( &xTimeOut );
-
xEntryTimeSet = pdTRUE;
-
}
-
}
-
}
-
taskEXIT_CRITICAL();
-
/* 退出臨界區,至此,中斷和其它任務可以向這個佇列執行入隊(投遞)或出隊(讀取)操作.因為佇列滿,任務無法入隊,下面的程式碼將當前任務將阻塞在這個佇列上,在這段程式碼執行過程中我們需要掛起排程器,防止其它任務操作佇列事件列表;掛起排程器雖然可以禁止其它任務操作這個佇列,但並不能阻止中斷服務程式操作這個佇列,因此還需要將佇列上鎖,防止中斷程式讀取佇列後,使阻塞在出隊操作其它任務解除阻塞,執行上下文切換(因為排程器掛起後,不允許執行上下文切換) */
-
vTaskSuspendAll();
-
prvLockQueue( pxQueue );
-
/* 檢視任務的超時時間是否到期 */
-
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
-
{
-
if( prvIsQueueFull( pxQueue ) != pdFALSE )
-
{
-
/*超時時間未到期,並且佇列仍然滿*/
-
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
-
/* 解除佇列鎖,如果有任務要解除阻塞,則將任務移到掛起就緒列表中(因為當前排程器掛起,所以不能移到就緒列表)*/
-
prvUnlockQueue( pxQueue );
-
/* 恢復排程器,將任務從掛起就緒列表移到就緒列表中*/
-
if( xTaskResumeAll() == pdFALSE )
-
{
-
portYIELD_WITHIN_API();
-
}
-
}
-
else
-
{
-
/* 佇列有空閒,重試 */
-
prvUnlockQueue( pxQueue );
-
( void ) xTaskResumeAll();
-
}
-
}
-
else
-
{
-
/* 超時時間到期,返回佇列滿錯誤碼*/
-
prvUnlockQueue( pxQueue );
-
( void ) xTaskResumeAll();
-
traceQUEUE_SEND_FAILED( pxQueue );
-
return errQUEUE_FULL;
-
}
-
}
-
}
- 程式流程如圖2-1所示,我們對圖中紅色字型標註的部分做詳解。
圖2-1:通用入隊操作流程圖
當任務將資料入隊時,如果佇列未滿或者以覆蓋式入隊,情況是最簡單的,呼叫函式prvCopyDataToQueue()將要入隊的資料拷貝到佇列。這個函式處理三種入隊情況,第一種是佇列項大小為0時(即佇列結構體成員uxItemSize為0,比如二進位制訊號量和計數訊號量),不進行資料拷貝工作,而是將佇列項計數器加1(即佇列結構體成員uxMessagesWaiting++);第二種情況是從佇列尾入隊時,則將資料拷貝到指標pxQueue->pcWriteTo指向的地方、更新指標指向的位置、佇列項計數器加1;第三種情況是從佇列首入隊時,則將資料拷貝到指標pxQueue->u.pcReadFrom指向的地方、更新指標指向的位置、佇列項計數器加1。如果是覆蓋式入隊,還會調整佇列項計數器的值。
完成資料入隊操作後,還要檢查是否有任務因為等待出隊而阻塞,因為這次資料入隊,佇列至少有一個佇列項,如果有阻塞任務,則阻塞的最高優先順序任務可以解除阻塞了。
因等待出隊而阻塞的任務會將任務的事件列表項(即任務TCB結構體成員xEventListItem,我們在《FreeRTOS高階篇2---FreeRTOS任務建立分析》一文中講到過事件列表項,它是任務TCB的一個結構體成員)掛接到佇列的等待出隊列表上(即佇列結構體成員xTasksWaitingToReceive)。現在,因為要解除任務阻塞,我們需要將任務的事件列表項從佇列的等待出隊佇列上刪除,並且將任務移動到就緒列表中。這一切,都是呼叫函式xTaskRemoveFromEventList()實現的。
之後,如果解除阻塞的任務優先順序比當前任務優先順序更高,則觸發一個PendSV中斷,等退出臨界區後,進行上下文切換。入隊任務完成。
上面討論了最理想的情況,過程也簡潔明瞭,但如果任務入隊時,佇列滿並且不允許覆蓋入隊,則情況會變得複雜起來。
在這種情況下,先看一個簡單分支:阻塞時間為0的情況。設定阻塞時間為0意味著當佇列滿時,函式立即返回,返回一個錯誤程式碼,表示佇列滿。
如果阻塞時間不為0,則本任務會因為等待入隊而進入阻塞。在將任務設定為阻塞的過程中,是不希望有其它任務和中斷操作這個佇列的事件列表的(佇列結構體成員xTasksWaitingToReceive列表和xTasksWaitingToSend列表),因為操作佇列事件列表可能引起其它任務解除阻塞,這可能會發生優先順序翻轉。比如任務A的優先順序低於本任務,但是在本任務進入阻塞的過程中,任務A卻因為其它原因解除阻塞了,這顯然是要絕對禁止的。因此FreeRTOS使用掛起排程器來簡單粗暴的禁止其它任務操作佇列,因為掛起排程器意味著任務不能切換並且不準呼叫可能引起任務切換的API函式。
但掛起排程器並不會禁止中斷,中斷服務函式仍然可以操作佇列事件列表,可能會解除任務阻塞、可能會進行上下文切換,這是不允許的。於是,解決辦法是不但掛起排程器,還要給佇列上鎖!
佇列結構體中有兩個成員跟佇列上鎖有關:xRxLock和xTxLock。這兩個成員變數為queueUNLOCKED(巨集,定義為-1)時,表示佇列未上鎖;當這兩個成員變數為queueLOCKED_UNMODIFIED(巨集,定義為0)時,表示佇列上鎖。
給佇列上鎖是呼叫巨集prvLockQueue()實現的,程式碼很簡單,將佇列結構體成員xRxLock和xTxLock都設定為queueLOCKED_UNMODIFIED。
我們看一下給佇列上鎖是如何起作用的。當中斷服務程式操作佇列並且導致阻塞的任務解除阻塞時,會首先判斷該佇列是否上鎖,如果沒有上鎖,則解除被阻塞的任務,還會根據需要設定上下文切換請求標誌;如果佇列已經上鎖,則不會解除被阻塞的任務,取而代之的是,將xRxLock或xTxLock加1,表示佇列上鎖期間出隊或入隊的數目,也表示有任務可以解除阻塞了。這部分程式碼在帶中斷保護的入隊和出隊API函式中,後面我們會講到,這裡先有個印象。
有將佇列上鎖操作,就會有解除佇列鎖操作。函式prvUnlockQueue()用於解除佇列鎖,將可以解除阻塞的任務插入到就緒列表,解除任務的最大數量由xRxLock和xTxLock指定。
經過一系列的邏輯判斷,發現本任務還是要進入阻塞狀態,則呼叫函式vTaskPlaceOnEventList()來實現。這個函式將揭示任務因等待特定事件而進入阻塞的詳細步驟,其實非常簡單,只有兩步:第一步,將任務的事件列表項(任務TCB結構體成員xEventListItem)插入到佇列的等待入隊列表(佇列結構體成員xTasksWaitingToSend)中;第二步,將任務的狀態列表項(任務TCB結構體成員xStateListItem)從就緒列表中刪除,然後插入到延時列表中,任務的最大延時時間放入xStateListItem. xItemValue中,每次系統節拍定時器中斷服務函式中,都會檢查這個值,檢測任務是否超時。
當任務成功阻塞在等待入隊操作後,當前任務就沒有必要再佔用CPU了,所以接下來解除佇列鎖、恢復排程器、進行任務切換,下一個處於最高優先順序的就緒任務就會被運行了。2.2 xQueueGenericSendFromISR ()
這個函式用於入隊,用於中斷服務程式中。根據引數的不同,可以從佇列尾入隊、從佇列首入隊也可以覆蓋式入隊。覆蓋式入隊用於只有一個佇列項的場合,入隊時如果佇列已滿,則將之前的佇列項覆蓋掉。函式原型為: -
BaseType_t xQueueGenericSendFromISR
-
(
-
QueueHandle_t xQueue,
-
const void * const pvItemToQueue,
-
BaseType_t * const pxHigherPriorityTaskWoken,
-
const BaseType_t xCopyPosition
-
)
- xQueue:佇列控制代碼。
- pvItemToQueue:指標,指向要入隊的專案。
- pxHigherPriorityTaskWoken:如果入隊導致一個任務解鎖,並且解鎖的任務優先順序高於當前執行的任務,則該函式將*pxHigherPriorityTaskWoken設定成pdTRUE。如果xQueueSendFromISR()設定這個值為pdTRUE,則中斷退出前需要一次上下文切換。從FreeRTOS V7.3.0起,pxHigherPriorityTaskWoken稱為一個可選引數,並可以設定為NULL。
- xCopyPosition:入隊位置,可以選擇從佇列尾入隊、從佇列首入隊和覆蓋式入隊。
- 這個函式和xQueueGenericSend()很相似,但是當佇列滿時不會阻塞,直接返回一個錯誤碼,表示佇列滿(相當於阻塞時間為0)。因此,有了分析xQueueGenericSend()的基礎,這個函式我們很快就能看完。原始碼簡化後如下所示:
-
BaseType_t xQueueGenericSendFromISR(
-
QueueHandle_t xQueue,
-
const void * const pvItemToQueue,
-
BaseType_t * const pxHigherPriorityTaskWoken,
-
const BaseType_t xCopyPosition )
-
{
-
BaseType_t xReturn;
-
UBaseType_t uxSavedInterruptStatus;
-
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
-
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
-
{
-
if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
-
{
-
traceQUEUE_SEND_FROM_ISR( pxQueue );
-
/*完成資料拷貝工作,分為從佇列尾入隊,從佇列首入隊和覆蓋式入隊*/
-
( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
-
/*檢查佇列是否上鎖,如果上鎖,則佇列事件列表不能被改變 */
-
if( pxQueue->xTxLock == queueUNLOCKED )
-
{ /*佇列沒有上鎖*/
-
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-
{
-
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-
{
-
/* 解除阻塞的任務優先順序比當前任務高,記錄上下文切換請求,等返回中斷服務程式後,可以顯示的強制上下文切換 */
-
if( pxHigherPriorityTaskWoken != NULL )
-
{
-
*pxHigherPriorityTaskWoken = pdTRUE;
-
}
-
}
-
}
-
}
-
else
-
{
-
/* 佇列上鎖,增加鎖計數器,等到任務解除佇列鎖時,使用這個計數器就可以知道有多少資料入隊,可以最多解除多少個因等待從佇列讀資料而阻塞的任務 */
-
++( pxQueue->xTxLock );
-
}
-
xReturn = pdPASS;
-
}
-
else
-
{
-
xReturn = errQUEUE_FULL;
-
}
-
}
-
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
-
return xReturn;
-
}
- 因為沒有阻塞,所以程式碼簡單了很多,唯一值得注意的是,當成功入隊後,如果有因為等待出隊而阻塞的任務,現在可以將其中最高優先順序的任務解除阻塞,在執行解除阻塞操作之前,會判斷佇列是否上鎖。如果沒有上鎖,則解除被阻塞的任務,還會根據需要設定上下文切換請求標誌;如果佇列已經上鎖,則不會解除被阻塞的任務,取而代之的是將xTxLock加1,表示佇列上鎖期間入隊的個數,也表示有任務可以解除阻塞了。
3.出隊
出隊的API函式要相對少一些,也分為帶中斷保護的出隊操作和不帶中斷保護的出隊操作。每種出隊情況都可以選擇是否刪除佇列項。出隊API函式如表3-1所示。表3-1:出隊API介面列表
出隊操作和入隊操作有很多相似性,將入隊流程理解透徹,出隊操作不在話下,因此我們不再分析原始碼。 --------------------- 本文來自 zhzht19861011 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/zhzht19861011/article/details/51510384?utm_source=copy
相關推薦
FreeRTOS高階篇5---FreeRTOS佇列分析
FreeRTOS提供了多種任務間通訊方式,包括: 任務通知(版本V8.2以及以上版本) 佇列 二進位制訊號量 計數訊號量 互斥量 遞迴互斥量 其中,二進位制訊號量、計數訊號量、互斥量和遞迴互斥量都是使用佇列來實
FreeRTOS高階篇11---空閒任務分析
當RTOS排程器開始工作後,為了保證至少有一個任務在執行,空閒任務被自動建立,佔用最低優先順序(0優先順序)。 xReturn = xTaskCreate( prvIdleTask
FreeRTOS高階篇7---FreeRTOS記憶體管理分析
記憶體管理對應用程式和作業系統來說都非常重要。現在很多的程式漏洞和執行崩潰都和記憶體分配使用錯誤有關。 FreeRTOS作業系統將核心與記憶體管理分開實現,作業系統核心僅規定了必要的記憶體管理函式原型,而不關心這些記憶體管理函式是如何實現的。這樣做大有好處,可以
FreeRTOS高階篇6---FreeRTOS訊號量分析
FreeRTOS的訊號量包括二進位制訊號量、計數訊號量、互斥訊號量(以後簡稱互斥量)和遞迴互斥訊號量(以後簡稱遞迴互斥量)。關於它們的區別可以參考《 FreeRTOS系列第19篇---
C語言高階篇 - 5.記憶體
1、馮諾依曼結構和哈佛結構 (1)馮諾依曼結構是:資料和程式碼放在一起。 (2)哈佛結構是:資料和程式碼分開存在。 (3)什麼是程式碼:函式 &nbs
Java高階篇-5-Arrays類
前面介紹了字串的操作的String類,這篇,我們學習陣列類,Java中提供了一個數組常見操作方法的類Arrays.java。其實前面也說過,String其實原始碼中就是用一個char[]
Esp8266 進階之路26【高階篇】RTOS移植分析 MQTT 實現過程,實現移植 MQTT協議在 esp8266 rtos實時系統,可斷線重連。(附帶Demo)
一、前言; esp8266的實時系統rtos是後面才出來支援的,其最後的呼叫也是呼叫樂鑫提供的API介面,所以,如果你已經玩轉了NONOS下的程式設計,那麼移植rtos程式碼是非常迅捷的,因為你已經對其的API介面非常熟悉,當然了
FreeRTOS(17)---FreeRTOS 佇列分析
FreeRTOS 佇列分析 FreeRTOS 佇列分析 佇列建立函式 入隊 xQueueGenericSend() xQueueGenericSendFromISR () 出隊
FreeRTOS學習筆記5-靜態方式創建任務函數
api函數 depth 還需要 而不是 ica alloc nbsp 分配 類型 配置完成後的進行任務創建,使用靜態方式創建任務時需要使將宏 configSUPPORT_STATIC_ALLOCATION設置為 1,即使用靜態內存。還需要將函數 vApplicationGe
C#高階篇(5)
1.反射和特性 有關程式以及型別的資料被稱為元資料,特們儲存在程式的程式集中。 程式在執行時,可以檢視其他程式及或其本身的元資料。一個執行的程式檢視本身元資料或者其他程式集的元資料的行為叫做反射。 Type類是抽象類,用來包含型別的特性。 GetFields獲取類中的相關屬性(公有的
FreeRTOS(9)---FreeRTOS 佇列
FreeRTOS 佇列 佇列是主要的任務間通訊方式。可以在任務與任務間、中斷和任務間傳送資訊。大多數情況下,佇列用於具有執行緒保護的FIFO(先進先出)緩衝區:新資料放在佇列的後面。當然,資料也可以放在佇列的前面,在下一篇講佇列API函式時,會涉及到資料的存放
FreeRTOS(10)---FreeRTOS 佇列API函式
FreeRTOS 佇列API函式 FreeRTOS為操作佇列提供了非常豐富的API函式,包括佇列的建立、刪除,靈活的入隊和出隊方式、帶中斷保護的入隊和出隊等等。下面就來詳細講述這些API函式。 獲取佇列入隊資訊數目 函式描述 UBaseType_t uxQue
FreeRTOS(15)---FreeRTOS 排程器啟動過程分析
FreeRTOS 排程器啟動過程分析 使用FreeRTOS,一個最基本的程式架構如下所示: int main(void) { 必要的初始化工作; 建立任務1; 建立任務2; ... vTaskStartSchedule
FreeRTOS(18)---FreeRTOS 訊號量分析
FreeRTOS 訊號量分析 FreeRTOS的訊號量包括二進位制訊號量、計數訊號量、互斥訊號量(以後簡稱互斥量)和遞迴互斥訊號量(以後簡稱遞迴互斥量)。關於它們的區別可以參考《 FreeRTOS系列第19篇—FreeRTOS訊號量》一文。 訊號量API函式實
shiro原始碼分析篇5:結合redis實現session跨域
相信大家對session跨域也比較瞭解了。以前單臺伺服器session本地快取就可以了,現在分散式後,session集中管理,那麼用redis來管理是一個非常不錯的選擇。 在結合redis做session快取的時候,也遇到了很多坑,不過還算是解決了。 和上篇講述一樣,實現自定義快
Spark修煉之道(高階篇)——Spark原始碼閱讀:第十二節 Spark SQL 處理流程分析
作者:周志湖 下面的程式碼演示了通過Case Class進行表Schema定義的例子: // sc is an existing SparkContext. val sqlContext = new org.apache.spark.sql.SQLConte
[資料庫系統基礎:高階篇(第5版)pdf
下載地址:網盤下載目錄第一部分 事務處理的概念第1章 事務處理的概念與理論簡介1.1 事務處理簡介1.2 事務和系統概念1.3 事務的描述特性1.4 描述基於可恢復性排程的特徵1.5 描述基於可序列性排程的特徵1.6 SQL中的事務支援小結複習題練習題參考文獻第2章 併發控制
FreeRTOS(23)---FreeRTOS 空閒任務分析
FreeRTOS 空閒任務分析 FreeRTOS 空閒任務分析 釋放記憶體 處理空閒優先順序任務 執行空閒任務鉤子函式 低功耗tickless模式 FreeRTOS 空閒任務分析 當RTOS排程器
FreeRTOS(22)---FreeRTOS 系統節拍時鐘分析
FreeRTOS 系統節拍時鐘分析 FreeRTOS 系統節拍時鐘分析 排程器正常情況 排程器掛起情況 自動任務切換 FreeRTOS 系統節拍時鐘分析 作業系統的執行是由系統節拍時鐘驅動的。 在Fr
FreeRTOS(21)---FreeRTOS 系統延時分析
FreeRTOS 系統延時分析 FreeRTOS 系統延時分析 相對延時函式vTaskDelay() 絕對延時函式vTaskDelayUntil() 小結 FreeRTOS 系統延時分析 FreeRTOS