1. 程式人生 > 實用技巧 >管道:介紹和基本服務

管道:介紹和基本服務

管道:介紹和基本服務

Pipes: introduction and basic services

與郵箱或佇列相比,它們提供了在任務之間傳遞簡單訊息的更靈活的方式。

使用管道

在Nucleus SE中,管道是在構建時配置的。一個應用程式最多可以配置16個管道。如果未配置管道,則應用程式中不會包含與管道相關的資料結構或服務呼叫程式碼。

管道僅僅是一組儲存位置,每個儲存位置都足夠大,足以容納一個使用者定義位元組長度的資料項,對這些資料項的訪問是受控制的,以便可以由多個任務安全地使用它。任務可以重複寫入管道,直到所有位置都已滿。任務可以從管道中讀取,資料通常以先進先出(FIFO)的方式接收。嘗試傳送到完整管道或從空管道讀取可能會導致錯誤或任務掛起,具體取決於在API呼叫和Nucleus SE配置中選擇的選項。

管道和佇列

Nucleus SE還支援佇列,管道和佇列之間的主要區別是訊息大小。佇列攜帶由單個ADDR組成的訊息,這些地址通常是指標。管道承載任意位元組長的訊息;應用程式中每個管道的大小是固定的,並在配置時設定。

配置管道

管道數量

與Nucleus SE的大多數方面一樣,管道的配置主要由nuse_config.h中的#define語句控制。鍵設定是NUSE_PIPE_NUMBER,它確定為應用程式配置了多少個管道。預設設定為0(即沒有管道正在使用),您可以將其設定為最大16的任何值。錯誤的值將導致編譯時錯誤,該錯誤由nuse_config_check.h中的測試生成(此錯誤包含在nuse_config.c中,因此使用此模組進行編譯),從而導致編譯一個#錯誤語句。

選擇非零值是管道的“主啟用”。這將導致一些資料結構被相應地定義和調整大小,在下一篇文章中會有更多內容。它還啟用API啟用設定。

API啟用

Nucleus SE中的每個API函式(服務呼叫)在nuse_config.h中都有一個啟用的#define符號。對於管道,包括:

NUSE_PIPE_SEND
NUSE_PIPE_RECEIVE
NUSE_PIPE_JAM
NUSE_PIPE_RESET
NUSE_PIPE_INFORMATION
NUSE_PIPE_COUNT

預設情況下,所有這些都設定為FALSE,從而禁用每個服務呼叫並禁止包含任何實現程式碼。要為應用程式配置管道,需要選擇要使用的API呼叫,並將其啟用符號設定為TRUE。

下面是從預設nuse_config.h檔案中提取的內容。

#define NUSE_PIPE_NUMBER 0 /* Number of pipes in the
system – 0-16 */
/* Service call enablers */
#define NUSE_PIPE_SEND FALSE
#define NUSE_PIPE_RECEIVE FALSE
#define NUSE_PIPE_JAM FALSE
#define NUSE_PIPE_RESET FALSE
#define NUSE_PIPE_INFORMATION FALSE
#define NUSE_PIPE_COUNT FALSE

如果啟用了管道API函式而未配置管道(除非始終允許使用NUSE_pipe_Count()),則會導致編譯時錯誤。如果您的程式碼使用尚未啟用的API呼叫,則會導致連結時間錯誤,因為應用程式中不會包含任何實現程式碼。

管道服務電話

Nucleus RTOS支援10個與管道相關的服務呼叫,它們提供以下功能:

向管道傳送訊息。由Nucleus SE中的NUSE_Pipe_Send()實現。

從管道接收訊息。由Nucleus SE中的NUSE_Pipe_Receive()實現。

在管道前面發個資訊。由Nucleus SE中的NUSE_Pipe_Jam()實現。

將管道恢復到未使用狀態,不暫停任何任務(重置)。由Nucleus SE中的NUSE_Pipe_Reset()實現。

提供有關指定管道的資訊。由Nucleus SE中的NUSE_Pipe_Information()實現。

返回(當前)為應用程式配置的管道數的計數。由Nucleus SE中的NUSE_Pipe_Count()實現。

嚮應用程式新增新管道(建立)。未在Nucleus SE中實現。

從應用程式中刪除管道(刪除)。未在Nucleus SE中實現。

返回指向應用程式中所有管道(當前)的指標。未在Nucleus SE中實現。

向管道(廣播)上掛起的所有任務傳送訊息。未在Nucleus SE中實現。

將詳細檢查每個服務呼叫的實現。

管道讀寫服務

可以在管道上執行的基本操作是向管道寫入資料(有時稱為傳送)和從中讀取資料(也稱為接收)。也可以將資料寫入管道前端,這也被稱為堵塞。Nucleus RTOS和Nucleus SE各自為這些操作提供了三個基本API呼叫,這裡將對此進行討論。

寫在管道上

Nucleus RTOS API對管道的寫入呼叫非常靈活,允許您無限期地掛起,或者在操作無法立即完成的情況下暫停,也就是說,您嘗試寫入一個完整的管道。Nucleus SE提供相同的服務,除了task suspend是可選的並且不實現timeout。

Nucleus RTOS還提供了一個向管道廣播的功能,但Nucleus SE不支援這種功能。

Nucleus RTOS API Call for Sending to a Pipe

Service call prototype:

STATUS NU_Send_To_Pipe(NU_PIPE *pipe, VOID *message,
UNSIGNED size, UNSIGNED suspend);

Parameters:

pipe– pointer to the user-supplied pipe control block
message– a pointer to the message to be sent
size– the number of bytes in the message. If the pipe supports variable-length messages, this parameter must be equal to or less than the message size supported by the pipe. If the pipe supports fixed-size messages, this parameter must be exactly the same as the message size supported by the pipe
suspend– specification for task suspend; may beNU_NO_SUSPENDorNU_SUSPENDor a timeout value

Returns:

NU_SUCCESS– the call was completed successfully
NU_INVALID_PIPE– the pipe pointer is invalid
NU_INVALID_POINTER– the message pointer isNULL
NU_INVALID_SIZE– the message size is incompatible with the message size supported by the pipe
NU_INVALID_SUSPEND– suspend was attempted from a non-task thread
NU_PIPEE_FULL– the pipe is full and suspend was not specified
NU_TIMEOUT– the pipe is still full even after suspending for the specified timeout value
NU_PIPE_DELETED– the pipe was deleted while the task was suspended
NU_PIPE_RESET– the pipe was reset while the task was suspended

Nucleus SE API Call for Sending to a Pipe

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

<="" font="" >

<="" font="" >

STATUS NUSE_Pipe_Send(NUSE_PIPE pipe, U8 *message,
U8 suspend);

Parameters:

pipe– the index (ID) of the pipe to be utilized
message– a pointer to the message to be sent, which is a sequence of bytes as long as the configured message size of the pipe
suspend– specification for task suspend; may beNUSE_NO_SUSPENDorNUSE_SUSPEND

Returns:

NUSE_SUCCESS– the call was completed successfully
NUSE_INVALID_PIPE– the pipe index is invalid
NUSE_INVALID_POINTER– the message pointer isNULL
NUSE_INVALID_SUSPEND– suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_FULL– the pipe is full and suspend was not specified
NUSE_PIPE_WAS_RESET– the pipe was reset while the task was suspended

管道傳送的核SE實現

NUSE_Pipe_Send()–檢查API函式是否已啟用suspend()的條件編譯(取決於u)的API是否已啟用。我們將在這裡分別研究這兩種變體。

如果未啟用阻塞,則此API呼叫的程式碼非常簡單:

if(NUSE_Pipe_Items[pipe]==NUSE_Pipe_Size[pipe])/*pipefull*/{return_value=NUSE_PIPE_FULL;}else/*pipeelementavailable*/{data=&NUSE_Pipe_Data[pipe][NUSE_Pipe_Head[pipe]];for(i=0;i<msgsize;i++){*data++=*message++;}NUSE_Pipe_Head[pipe]+=msgsize;if(NUSE_Pipe_Head[pipe]==(NUSE_Pipe_Size[pipe]*msgsize)){NUSE_Pipe_Head[pipe]=0;}NUSE_Pipe_Items[pipe]++;return_value=NUSE_SUCCESS;}

該函式只檢查管道中是否有空間,並使用NUSE_pipe_Head[]索引將訊息儲存在管道的資料區域中。

啟用阻塞後,程式碼會變得更復雜:

do{if(NUSE_Pipe_Items[pipe]==NUSE_Pipe_Size[pipe])/*pipefull*/{if(suspend==NUSE_NO_SUSPEND){return_value=NUSE_PIPE_FULL;}else{/*blocktask*/NUSE_Pipe_Blocking_Count[pipe]++;NUSE_Suspend_Task(NUSE_Task_Active,(pipe<<4)|NUSE_PIPE_SUSPEND);return_value=NUSE_Task_Blocking_Return[NUSE_Task_Active];if(return_value!=NUSE_SUCCESS){suspend=NUSE_NO_SUSPEND;}}}else/*pipeelementavailable*/{data=&NUSE_Pipe_Data[pipe][NUSE_Pipe_Head[pipe]];for(i=0;i<msgsize;i++){*data++=*message++;}NUSE_Pipe_Head[pipe]+=msgsize;if(NUSE_Pipe_Head[pipe]==(NUSE_Pipe_Size[pipe]*msgsize)){NUSE_Pipe_Head[pipe]=0;}NUSE_Pipe_Items[pipe]++;if(NUSE_Pipe_Blocking_Count[pipe]!=0){U8index;/*checkwhetherataskisblockedonthispipe*/NUSE_Pipe_Blocking_Count[pipe]--;for(index=0;index<NUSE_TASK_NUMBER;index++){if((LONIB(NUSE_Task_Status[index])==NUSE_PIPE_SUSPEND)&&(HINIB(NUSE_Task_Status[index])==pipe)){NUSE_Task_Blocking_Return[index]=NUSE_SUCCESS;NUSE_Wake_Task(index);break;}}}return_value=NUSE_SUCCESS;suspend=NUSE_NO_SUSPEND;}}while(suspend==NUSE_SUSPEND);

對程式碼的一些解釋可能有用:

程式碼包含在do…while迴圈中,當引數suspend的值為NUSE_suspend時,迴圈將繼續。

如果管道已滿,並且suspend設定為NUSE_NO_suspend,則API呼叫將以NUSE_pipe_full退出。如果suspend設定為NUSE_suspend,則任務將被掛起。返回時(即,當任務被喚醒時),如果返回值為NUSE_SUCCESS,表示任務被喚醒是因為訊息已被讀取(而不是重置管道),則程式碼迴圈返回頂部。

如果管道未滿,則使用NUSE_pipe_Head[]索引儲存提供的訊息,以將訊息儲存在管道的資料區域中。檢查管道上是否有任何任務掛起(等待接收)。如果有任務等待,第一個任務被喚醒。suspend變數被設定為NUSE_NO_suspend,API呼叫將退出並返回NUSE_SUCCESS。

從管子裡讀東西

從管道讀取的Nucleus RTOS API呼叫非常靈活,使您能夠無限期地掛起,或者在操作無法立即完成的情況下暫停,也就是說,您嘗試從空管道中讀取。Nucleus SE提供相同的服務,除了task suspend是可選的並且不實現timeout。

ucleus RTOS API Call for Receiving from a Pipe

Service call prototype:

STATUS NU_Receive_From_Pipe(NU_PIPE *pipe, VOID *message, UNSIGNED size, UNSIGNED *actual_size, UNSIGNED suspend);

Parameters:

pipe– pointer to user-supplied pipe control block
message– pointer to storage for the message to be received
size– the number of bytes in the message. This number must correspond to the message size defined when the pipe was created
suspend– specification for task suspend; may beNU_NO_SUSPENDorNU_SUSPENDor a timeout value

Returns:

NU_SUCCESS– the call was completed successfully
NU_INVALID_PIPE– the pipe pointer is invalid
NU_INVALID_POINTER– the message pointer isNULL
NU_INVALID_SUSPEND– suspend was attempted from a non-task
NU_PIPE_EMPTY– the pipe is empty and suspend was not specified
NU_TIMEOUT– indicates that the pipe is still empty even after suspending for the specified timeout value
NU_PIPE_DELETED– the pipe was deleted while the task was suspended
NU_PIPE_RESET– the pipe was reset while the task was suspended

Nucleus SE API Call for Receiving from a Pipe

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

STATUS NUSE_Pipe_Receive(NUSE_PIPE pipe, U8 *message,
U8 suspend);

Parameters:

pipe– the index (ID) of the pipe to be utilized
message– a pointer to storage for the message to be received, which is a sequence of bytes as long as the configured message size of the pipe
suspend– specification for task suspend; may beNUSE_NO_SUSPENDorNUSE_SUSPEND

Returns:

NUSE_SUCCESS– the call was completed successfully
NUSE_INVALID_PIPE– the pipe index is invalid
NUSE_INVALID_POINTER– the message pointer isNULL
NUSE_INVALID_SUSPEND– suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_EMPTY– the pipe is empty and suspend was not specified
NUSE_PIPE_WAS_RESET– the pipe was reset while the task was suspended

Nucleus SE Implementation of Pipe Receive

管道接收的核SE實現

NUSE_Pipe_Receive()API函式的大部分程式碼(在引數檢查之後)是通過條件編譯選擇的,這取決於是否啟用了對阻塞(任務掛起)API呼叫的支援。我們將在這裡分別研究這兩種變體。

如果未啟用阻塞,則此API呼叫的程式碼非常簡單:

if(NUSE_Pipe_Items[pipe]==0)/*pipeempty*/{return_value=NUSE_PIPE_EMPTY;}else{/*messageavailable*/data=&NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]];for(i=0;i<msgsize;i++){*message++=*data++;}NUSE_Pipe_Tail[pipe]+=msgsize;if(NUSE_Pipe_Tail[pipe]==(NUSE_Pipe_Size[pipe]*msgsize)){NUSE_Pipe_Tail[pipe]=0;}NUSE_Pipe_Items[pipe]--;*actual_size=msgsize;return_value=NUSE_SUCCESS;}

只需使用管道中的指標NUSE_Pipe_Tail[]從資料管道中返回資料,並通過管道返回資料。 啟用阻塞後,程式碼會變得更復雜:

do{if(NUSE_Pipe_Items[pipe]==0)/*pipeempty*/{if(suspend==NUSE_NO_SUSPEND){return_value=NUSE_PIPE_EMPTY;}else{/*blocktask*/NUSE_Pipe_Blocking_Count[pipe]++;NUSE_Suspend_Task(NUSE_Task_Active,(pipe<<4)|NUSE_PIPE_SUSPEND);return_value=NUSE_Task_Blocking_Return[NUSE_Task_Active];if(return_value!=NUSE_SUCCESS){suspend=NUSE_NO_SUSPEND;}}}else{/*messageavailable*/data=&NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]];for(i=0;i<msgsize;i++){*message++=*data++;}NUSE_Pipe_Tail[pipe]+=msgsize;if(NUSE_Pipe_Tail[pipe]==(NUSE_Pipe_Size[pipe]*msgsize)){NUSE_Pipe_Tail[pipe]=0;}NUSE_Pipe_Items[pipe]--;if(NUSE_Pipe_Blocking_Count[pipe]!=0){U8index;/*checkwhetherataskisblocked*//*onthispipe*/NUSE_Pipe_Blocking_Count[pipe]--;for(index=0;index<NUSE_TASK_NUMBER;index++){if((LONIB(NUSE_Task_Status[index])==NUSE_PIPE_SUSPEND)&&(HINIB(NUSE_Task_Status[index])==pipe)){NUSE_Task_Blocking_Return[index]=NUSE_SUCCESS;NUSE_Wake_Task(index);break;}}}*actual_size=msgsize;return_value=NUSE_SUCCESS;suspend=NUSE_NO_SUSPEND;}}while(suspend==NUSE_SUSPEND);

對程式碼的一些解釋可能有用:

程式碼包含在do…while迴圈中,當引數suspend的值為NUSE_suspend時,迴圈將繼續。

如果管道為空,並且suspend設定為NUSE_NO_suspend,則API呼叫將以NUSE_pipe_empty退出。如果suspend設定為NUSE_suspend,則任務將被掛起。返回時(即,當任務被喚醒時),如果返回值為NUSE_SUCCESS,表示任務因已傳送訊息而被喚醒(而不是重置管道),則程式碼迴圈返回頂部。

如果管道包含任何訊息,則使用NUSE_pipe_Tail[]索引返回儲存的訊息,以從管道的資料區域獲取訊息。檢查管道上是否有任何任務被掛起(等待發送)。如果有任務等待,第一個任務被喚醒。suspend變數被設定為NUSE_NO_suspend,API呼叫將退出並返回NUSE_SUCCESS。

寫在管道前面

Nucleus RTOS-API呼叫寫入管道的前端非常靈活,允許您無限期地掛起,或者在操作無法立即完成的情況下暫停超時;也就是說,您嘗試寫入一個完整的管道。Nucleus SE提供相同的服務,除了task suspend是可選的並且不實現timeout。

Nucleus RTOS API Call for Jamming to a Pipe

Service call prototype:

STATUS NU_Send_To_Front_Of_Pipe(NU_PIPE *pipe, VOID *message,
UNSIGNED size, UNSIGNED suspend);

Parameters:

pipe– pointer to a user-supplied pipe control block
message– a pointer to the message to be sent
size– the number of bytes in the message. If the pipe supports variable-length messages, this parameter must be equal to or less than the message size supported by the pipe. If the pipe supports fixed-size messages, this parameter must be exactly the same as the message size supported by the pipe.
suspend– specification for task suspend; may beNU_NO_SUSPENDorNU_SUSPENDor a timeout value

Returns:

NU_SUCCESS– the call was completed successfully
NU_INVALID_PIPE– the pipe pointer is invalid
NU_INVALID_POINTER– the message pointer isNULL
NU_INVALID_SIZE– the message size is incompatible with the message size supported by the pipe
NU_INVALID_SUSPEND– suspend was attempted from a non-task thread
NU_PIPE_FULL– the pipe is full and suspend was not specified
NU_TIMEOUT– the pipe is still full even after suspending for the specified timeout value
NU_PIPE_DELETED– the pipe was deleted while the task was suspended
NU_PIPE_RESET– the pipe was reset while the task was suspended

Nucleus SE API Call for Jamming to a Pipe

This API call supports the key functionality of the Nucleus RTOS API.

Service call prototype:

STATUS NUSE_Pipe_Jam(NUSE_PIPE pipe, ADDR *message,
U8 suspend);

Parameters:

pipe– the index (ID) of the pipe to be utilized
message– a pointer to the message to be sent, which is a sequence of bytes as long as the configured message size of the pipe
suspend– specification for task suspend; may beNUSE_NO_SUSPENDorNUSE_SUSPEND

Returns:

NUSE_SUCCESS– the call was completed successfully
NUSE_INVALID_PIPE– the pipe index is invalid
NUSE_INVALID_POINTER– the message pointer isNULL
NUSE_INVALID_SUSPEND– suspend was attempted from a non-task thread or when blocking API calls were not enabled
NUSE_PIPE_FULL– the pipe is full and suspend was not specified
NUSE_PIPE_WAS_RESET– the pipe was reset while the task was suspended

Nucleus SE Implementation of Jamming to a Pipe

The bulk of the code of theNUSE_Pipe_Jam()API function is very similar to that ofNUSE_Pipe_Send(), except that the data is stored using theNUSE_Pipe_Tail[]index, thus:

if(NUSE_Pipe_Items[pipe]==NUSE_Pipe_Size[pipe])/*pipefull*/{return_value=NUSE_PIPE_FULL;}else/*pipeelementavailable*/{if(NUSE_Pipe_Tail[pipe]==0){NUSE_Pipe_Tail[pipe]=(NUSE_Pipe_Size[pipe]-1)*msgsize;}else{NUSE_Pipe_Tail[pipe]-=msgsize;}data=&NUSE_Pipe_Data[pipe][NUSE_Pipe_Tail[pipe]];for(i=0;i<msgsize;i++){*data++=*message++;}NUSE_Pipe_Items[pipe]++;return_value=NUSE_SUCCESS;}