在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

探索字節隊列的魔法:多類型支持、函數重載與線程安全

RT-Thread官方賬號 ? 2024-11-15 01:08 ? 次閱讀


探索字節隊列的魔法:多類型支持、函數重載與線程安全

代碼難度指數:

文章學習重點:參數宏的使用技巧

一、引言

嵌入式系統和實時應用中,數據的傳輸和處理是至關重要的。字節隊列(Byte Queue)是一種重要的數據結構,它能夠高效地存儲和管理數據流。通過使用字節隊列,我們可以靈活地處理不同類型的數據、確保數據的完整性,并在多線程環境中安全地進行操作。本文將深入探討字節隊列的概念、作用及其實現中的多類型支持、函數重載與線程安全機制。

1.1 隊列的基本概念

隊列是一種先進先出(FIFO,First In First Out)的數據結構。數據通過“入隊”(enqueue)操作添加到隊列的尾部,并通過“出隊”(dequeue)操作從隊列的頭部移除。在嵌入式系統中,隊列常用于:

  • 數據緩沖:在數據產生和消費速率不匹配的情況下,隊列可以暫存數據,平衡輸入和輸出之間的差異。
  • 任務調度:任務或事件的管理可以通過隊列來實現,確保它們按照特定順序被處理。
  • 通信:隊列可以在不同模塊或線程之間傳遞信息,從而實現模塊間的解耦和同步。

1.2 字節隊列的不足

盡管字節隊列在嵌入式系統中提供了基本的數據存儲與管理能力,但其在實際應用中也存在一些明顯的不足:

  • 缺乏多類型支持:傳統的字節隊列往往只能處理單一類型的數據,例如,使用固定的字節數組存儲數據,導致不同數據類型之間缺乏靈活性。為了支持不同類型的數據,開發者通常需要創建多個隊列,從而增加了代碼的復雜性和維護成本。
  • 沒有函數重載:在 C 語言中,函數重載是通過不同的函數名稱來實現的,缺乏類似 C++的靈活性。這使得在隊列操作中無法方便地處理不同數量和類型的參數,導致代碼冗長且不易維護。
  • 線程安全機制不足:在多線程環境中,若多個線程同時訪問字節隊列而沒有適當的同步機制,可能會導致數據損壞或不一致。傳統的字節隊列實現往往沒有內置的線程安全支持,增加了并發編程的難度。

二、字節隊列的改進

2.1 多類型支持的實現原理

問題: C 語言中的數組或緩沖區往往只能存儲單一類型的數據。例如,你可以定義一個 uint8_t 數組來存儲字節數據,或者一個 int32_t 數組來存儲整型數據。然而,在嵌入式系統中,我們常常需要處理各種類型的數據——8 位、16 位、32 位的整數、浮點數等等。為了避免為每種類型單獨創建隊列,我們希望有一個靈活的隊列,可以自動支持多種數據類型。

解決方案: 我們使用 C 語言的宏來解決這個問題。通過宏,隊列可以自動根據傳入的數據類型來計算所需的存儲空間。核心思想是:我們不關心具體的數據類型,而是通過宏和類型推導,計算每個數據需要的字節數,并按照字節的形式將數據存入隊列中。

使用 typeof 推斷數據類型:

C 語言的 typeof 關鍵字可以根據表達式自動推斷出數據類型,并可以通過該類型確定數據的大小。在我們的實現中,隊列的操作宏會通過 sizeof 來獲取傳入數據的字節大小。

示例:

#defineenqueue(queue,data)enqueue_bytes(queue,&data,sizeof(typeof(data)))

在上述宏中:

  • typeof(data) 會推斷出 data 的類型,然后通過 sizeof(typeof(data))確定該類型占用的字節數。
  • 通過將數據的地址傳遞給底層的 enqueue_bytes 函數,我們可以統一將所有類型的數據作為字節流處理。

通過這種方式,我們的隊列可以支持任意類型的數據,比如 8 位字節、16 位整數、32 位浮點數,甚至自定義的數據結構,只要知道它們的大小即可。

2.2 函數重載的實現原理

問題: 在 C++等語言中,函數重載允許你定義多個同名的函數,但參數類型或數量不同。然而,C 語言并不原生支持函數重載。這意味著如果我們想實現同名函數,處理不同類型或數量的參數,就需要想出另一種方法。

解決方案: 我們可以通過 C 語言的宏來“模擬”函數重載。宏的靈活性使得我們可以根據不同的參數數量或類型,選擇不同的底層函數進行處理。結合__VAARGS_等可變參數宏的特性,我們可以輕松實現這種重載行為。

使用宏實現參數數量的重載: enqueue 可以根據傳遞的參數數量,調用不同的函數。我們使用__VAARGS_(可變參數)來處理不同數量的參數。

enqueue 宏的完整代碼如下:

#define__CONNECT3(__A,__B,__C)__A##__B##__C
#define__CONNECT2(__A,__B)__A##__B

#defineCONNECT3(__A,__B,__C)__CONNECT3(__A,__B,__C)
#defineCONNECT2(__A,__B)__CONNECT2(__A,__B)
#defineSAFE_NAME(__NAME)CONNECT3(__,__NAME,__LINE__)

#define__PLOOC_VA_NUM_ARGS_IMPL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,\
_12,_13,_14,_15,_16,__N,...)__N


#define__PLOOC_VA_NUM_ARGS(...)\
__PLOOC_VA_NUM_ARGS_IMPL(0,##__VA_ARGS__,16,15,14,13,12,11,10,9,\
8,7,6,5,4,3,2,1,0)

#define__ENQUEUE_0(__QUEUE,__VALUE)\
({typeof((__VALUE))SAFE_NAME(value)=__VALUE;\
enqueue_bytes((__QUEUE),&(SAFE_NAME(value)),(sizeof(__VALUE)));})

#define__ENQUEUE_1(__QUEUE,__ADDR,__ITEM_COUNT)\
enqueue_bytes((__QUEUE),(__ADDR),__ITEM_COUNT*(sizeof(typeof((__ADDR[0])))))

#define__ENQUEUE_2(__QUEUE,__ADDR,__TYPE,__ITEM_COUNT)\
enqueue_bytes((__QUEUE),(__ADDR),(__ITEM_COUNT*sizeof(__TYPE)))

#defineenqueue(__queue,__addr,...)\
CONNECT2(__ENQUEUE_,__PLOOC_VA_NUM_ARGS(__VA_ARGS__))\
(__queue,(__addr),##__VA_ARGS__)

工作原理

通過以上代碼,enqueue宏會根據傳遞的參數數量,自動選擇不同的實現版本

  • 傳遞的可變參數如果為 0,調用__ENQUEUE_0;
  • 傳遞的可變參數如果為 1,調用__ENQUEUE_1;
  • 傳遞的可變參數如果為 2,調用__ENQUEUE_2。

2.2.1 函數重載的秘密 ——“__PLOOC_VA_NUM_ARGS”宏的深度剖析

__PLOOC_VA_NUM_ARGS 宏的代碼如下:

#define__PLOOC_VA_NUM_ARGS_IMPL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,\
_13,_14,_15,_16,__N,...)__N
#define__PLOOC_VA_NUM_ARGS(...)\
__PLOOC_VA_NUM_ARGS_IMPL(0,##__VA_ARGS__,16,15,14,13,12,11,10,9,\
8,7,6,5,4,3,2,1,0)

  1. __PLOOC_VA_NUM_ARGS 宏的作用是它可以告訴我們實際傳遞了多少個參數

這里,首先構造了一個特殊的參數宏,__PLOOC_VA_NUM_ARGS_IMPL():

  • 在涉及"..."之前,它要用戶至少傳遞 18 個參數;
  • 這個宏的返回值就是第十八個參數的內容;
  • 多出來的部分會被"..."吸收掉,不會產生任何后果

__PLOOC_VA_NUM_ARGS 的巧妙在于,它把__VA_ARGS__放在了參數列表的最前面,并隨后傳遞了 "16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0" 這樣的序號:

當__VA_ARGS__里有 1 個參數時,“1”對應第十八個參數__N,所以返回值是 1

當__VA_ARGS__里有 2 個參數時,“2”對應第十八個參數__N,所以返回值是 2

...

當__VA_ARGS__里有 9 個參數時,"9"對應第十八個參數__N,所以返回值是 9

舉個例子:

__PLOOC_VA_NUM_ARGS(0x,D,E,A,D)

展開為:

__PLOOC_VA_NUM_ARGS_IMPL(0,0x,D,E,A,D,16,15,14,13,12,11,10,9,\
8,7,6,5,4,3,2,1,0)

__PLOOC_VA_NUM_ARGS 的返回值是 5,從左往右數,第十八個參數,正好是“5”。

  1. 宏連接符##的作用

#define__CONNECT2(__A,__B)__A##__B
#defineCONNECT2(__A,__B)__CONNECT2(__A,__B)

宏連接符 ## 的主要作用就是連接兩個字符串,我們在宏定義中可以使用 ## 來連接兩個字符。預處理器在預處理階段對宏展開時,會將## 兩邊的字符合并,并刪除 ## 這兩個字符。

使用宏連接符 ##要注意一下兩條結論:

  • 第一條:任何使用到膠水運算“##”對形參進行粘合的參數宏,一定需要額外的再套一層
  • 第二條:其余情況下,如果要用到膠水運算,一定要在內部借助參數宏來完成粘合過程

為了理解這一“結論”,我們不妨舉一個例子:比如定義一個用于自動關閉中斷并在完成指定操作后自動恢復原來狀態的宏:

#defineSAFE_ATOM_CODE(...)\
{\
uint32_twTemp=__disable_irq();\
__VA_ARGS__;\
__set_PRIMASK(wTemp);\
}

由于這里定義了一個變量 wTemp,而如果用戶插入的代碼中也使用了同名的變量,就會產生很多問題:輕則編譯錯誤(重復定義);重則出現局部變量 wTemp 強行取代了用戶自定義的靜態變量的情況,從而直接導致系統運行出現隨機性的故障(比如隨機性的中斷被關閉后不再恢復,或是原本應該被關閉的全局中斷處于打開狀態等等)。為了避免這一問題,我們往往會想自動給這個變量一個不會重復的名字,比如借助 __LINE__ 宏給這一變量加入一個后綴:

#defineSAFE_ATOM_CODE(...)\
{\
uint32_twTemp##__LINE__=__disable_irq();\
__VA_ARGS__;\
__set_PRIMASK(wTemp);\
}

假設這里 SAFE_ATOM_CODE 所在行的行號是 123,那么我們期待的代碼展開是這個樣子的(我重新縮進過了):

...
{
uint32_twTemp123=__disable_irq();
__VA_ARGS__;
__set_PRIMASK(wTemp);
}
...

然而,實際展開后的內容是這樣的:

...
{
uint32_twTemp__LINE__=__disable_irq();
__VA_ARGS__;
__set_PRIMASK(wTemp);
}
...

這里,__LINE__似乎并沒有被正確替換為 123,而是以原樣的形式與 wTemp 粘貼到了一起——這就是很多人經常抱怨的 __LINE__ 宏不穩定的問題。實際上,這是因為上述宏的構建沒有遵守前面所列舉的兩條結論導致的。

從內容上看,SAFE_ATOM_CODE() 要粘合的對象并不是形參,根據結論第二條,需要借助另外一個參數宏來幫忙完成這一過程。為此,我們需要引入一個專門的宏:

#defineCONNECT2(__A,__B)__A##__B

注意到,這個參數宏要對形參進行膠水運算,根據結論第一條,需要在宏的外面再套一層,因此,修改代碼得到:

#define__CONNECT2(__A,__B)__A##__B
#defineCONNECT2(__A,__B)__CONNECT2(__A,__B)

修改前面的定義得到:

#defineSAFE_ATOM_CODE(...)\
{\
uint32_tCONNECT2(wTemp,__LINE__)=\
__disable_irq();\
__VA_ARGS__;\
__set_PRIMASK(wTemp);\
}

  1. 對 enqueue 的封裝進行展開

#defineenqueue(__queue,__addr,...)\
CONNECT2(__ENQUEUE_,__PLOOC_VA_NUM_ARGS(__VA_ARGS__))\
(__queue,(__addr),##__VA_ARGS__)

CONNECT2 會根據__PLOOC_VA_NUM_ARGS 返回的數量,與__ENQUEUE_進行連接,

  • __PLOOC_VA_NUM_ARGS 返回的數量如果為 0,調用__ENQUEUE_0(__queue,(__addr),##__VA_ARGS__);
  • __PLOOC_VA_NUM_ARGS 返回的數量如果為 1,調用__ENQUEUE_1(__queue,(__addr),##__VA_ARGS__);
  • __PLOOC_VA_NUM_ARGS 返回的數量如果為 2,調用__ENQUEUE_2(__queue,(__addr),##__VA_ARGS__);

舉個例子:

staticbyte_queue_tmy_queue;
uint8_tdata1=0XAA;
enqueue(&my_queue,data1);//__ENQUEUE_0(&my_queue,data1)
enqueue(&my_queue,&data1,1);//__ENQUEUE_1(&my_queue,&data1,1)
enqueue(&my_queue,&data1,uint8_t1);//__ENQUEUE_2(&my_queue,&data1,uint8_t,1)
/*__ENQUEUE_0,__ENQUEUE_1,__ENQUEUE_2,展開后調用的都是同一個接口*/
enqueue_bytes(&my_queue,&data1,1)

2.3 線程安全的實現原理

問題: 在多線程環境下,如果多個線程同時對同一個隊列進行操作,可能會引發數據競爭問題,導致數據損壞或不一致。為了避免這種情況,我們需要保證每次對隊列的操作是原子的,即不可打斷的。

解決方案: 在嵌入式系統中,常用的方法是通過禁用中斷或使用鎖機制來保證數據的一致性。在我們的實現中,我們使用禁用中斷的方式來確保線程安全。這是一種非常常見的技術,尤其是在實時系統中。

為了盡量降低關中斷對實時性的影響,我們只對操作隊列指針的操作進行關中斷保護,相對耗時間的數據拷貝不進行關中斷。

函數偽代碼如下:

boolenqueue_bytes(...)
{
boolbEarlyReturn=false;
safe_atom_code(){
if(!this.bMutex){
this.bMutex=true;
}else{
bEarlyReturn=true;
}
}
if(bEarlyReturn){
returnfalse;
}
safe_atom_code(){
/*隊列指針操作*/
...
}
/*數據操作*/
memcpy(...);
...
this.bMutex=false;
returntrue;
}

原子宏 safe_atom_code()的實現:

前邊的例子中,我們實現了一個 SAFE_ATOM_CODE 的原子宏,唯一的問題是,這樣的寫法,在調試時完全沒法在用戶代碼處添加斷點(編譯器會認為宏內所有的內容都寫在了同一行),這是大多數人不喜歡使用宏來封裝代碼結構的最大原因。

接下來我們用另一種實現方式來解決這個問題,代碼如下:

#define__CONNECT3(__A,__B,__C)__A##__B##__C
#define__CONNECT2(__A,__B)__A##__B
#defineCONNECT3(__A,__B,__C)__CONNECT3(__A,__B,__C)
#defineCONNECT2(__A,__B)__CONNECT2(__A,__B)
#defineSAFE_NAME(__NAME)CONNECT3(__,__NAME,__LINE__)
#include"cmsis_compiler.h"
#definesafe_atom_code()\
for(uint32_tSAFE_NAME(temp)=\
({uint32_tSAFE_NAME(temp2)=__get_PRIMASK();\
__disable_irq();\
SAFE_NAME(temp2);}),*SAFE_NAME(temp3)=NULL;\
SAFE_NAME(temp3)++==NULL;\
__set_PRIMASK(SAFE_NAME(temp)))
#endif

工作原理:

safe_atom_code()通過一個循環結構確保在隊列操作期間,中斷被禁用。循環結束后自動恢復中斷。

2.3.1 for 循環的妙用

首先構造一個只執行一次的 for 循環結構:

for(inti=1;i>0;i--){
...
}

對于這樣的 for 循環結構,幾個關鍵部分就有了新的意義:

  • 在執行用戶代碼之前(灰色部分),有能力進行一定的“準備工作”(Before 部分);
  • 在執行用戶代碼之后,有能力執行一定的“收尾工作”(After 部分);
  • 在 init_clause 階段有能力定義一個“僅僅只覆蓋” for 循環的,并且只對 User Code 可見的局部變量——換句話說,這些局部變量是不會污染 for 循環以外的地方的。

0f2f2148-a2ab-11ef-8084-92fbcf53809c.png

利用這樣的結構,我們很容易就能構造出一個可以通過花括號的形式來包裹用戶代碼的原子操作 safe_atom_code(),在執行用戶代碼之前關閉中斷,在執行完用戶代碼之后打開中斷,還不影響在用戶代碼中添加斷點,單步執行。

需要注意的是,如果需要中途退出循環,需要使用continue退出原子操作,不能使用break。

2.4 總結

通過上述的多類型支持、函數重載和線程安全的實現,我們大大增強了字節隊列的靈活性和實用性:

  1. 多類型支持: 自動推斷數據類型和大小,支持不同類型數據的隊列操作。
  2. 函數重載: 通過宏模擬 C 語言的函數重載,靈活處理不同數量和類型的參數。
  3. 線程安全: 通過禁用中斷機制確保隊列操作在多線程環境中的原子性,避免數據競爭問題。

這些改進使得我們的字節隊列不僅可以在單線程環境中高效運行,還能在復雜的多線程系統中保持數據的一致性與安全性。

三、API 接口

#definequeue_init(__queue,__buffer,__size,...)\
__PLOOC_EVAL(__QUEUE_INIT_,##__VA_ARGS__)\
(__queue,(__buffer),(__size),##__VA_ARGS__)

#definedequeue(__queue,__addr,...)\
__PLOOC_EVAL(__DEQUEUE_,##__VA_ARGS__)\
(__queue,(__addr),##__VA_ARGS__)

#defineenqueue(__queue,__addr,...)\
__PLOOC_EVAL(__ENQUEUE_,##__VA_ARGS__)\
(__queue,(__addr),##__VA_ARGS__)

#definepeek_queue(__queue,__addr,...)\
__PLOOC_EVAL(__PEEK_QUEUE_,##__VA_ARGS__)\
(__queue,(__addr),##__VA_ARGS__)

extern
byte_queue_t*queue_init_byte(byte_queue_t*ptObj,void*pBuffer,uint16_thwItemSize,boolbIsCover);

extern
boolreset_queue(byte_queue_t*ptObj);

extern
uint16_tenqueue_bytes(byte_queue_t*ptObj,void*pDate,uint16_thwDataLength);

extern
uint16_tdequeue_bytes(byte_queue_t*ptObj,void*pDate,uint16_thwDataLength);

extern
boolis_queue_empty(byte_queue_t*ptQueue);

extern
boolis_peek_empty(byte_queue_t*ptObj);

extern
uint16_tpeek_bytes_queue(byte_queue_t*ptObj,void*pDate,uint16_thwDataLength);

extern
voidreset_peek(byte_queue_t*ptQueue);

extern
voidget_all_peeked(byte_queue_t*ptQueue);

extern
uint16_tget_peek_status(byte_queue_t*ptQueue);

extern
voidrestore_peek_status(byte_queue_t*ptQueue,uint16_thwCount);

extern
uint16_tget_queue_count(byte_queue_t*ptObj);

extern
uint16_tget_queue_available_count(byte_queue_t*ptObj);

四、API 說明

  1. 初始化隊列

queue_init(__queue,__buffer,__size,...)

參數說明:

參數名描述
__QUEUE隊列的地址
__BUFFER隊列緩存的首地址
__BUFFER_SIZE隊列長度
可變參數是否覆蓋,默認否
  1. 入隊

#defineenqueue(__queue,__addr,...)

參數說明:

參數名描述
__QUEUE隊列的地址
__ADDR待入隊的數據或者數據的地址
...可變參數,需要入隊的數據個數,或者數據類型和個數,如果為空,則只入隊一個數據
  1. 出隊

#definedequeue(__queue,__addr,...)

參數說明:

參數名描述
__QUEUE隊列的地址
__ADDR用于保存出隊數據變量的地址
...可變參數,需要出隊的數據個數,或者數據類型和個數,如果為空,則只出隊一個數據
  1. 查看

#definepeek_queue(__queue,__addr,...)

參數說明:

參數名描述
__QUEUE隊列的地址
__ADDR用于保存查看數據變量的地址
...可變參數,數據類型和需要查看的數據個數,如果為空,則只查看一個數據

五、快速使用

代碼開源地址:https://github.com/Aladdin-Wang/wl_queue

或者打開MicroBoot,介紹鏈接:徹底解決單片機BootLoader升級程序失敗問題,只勾選queue,如圖所示:

0f3a7462-a2ab-11ef-8084-92fbcf53809c.png

使用實例:

#include"ring_queue.h"

uint8_tdata1=0XAA;
uint16_tdata2=0X55AA;
uint32_tdata3=0X55AAAA55;
uint16_tdata4[]={0x1234,0x5678};
typedefstructdata_t{
uint32_ta;
uint32_tb;
uint32_tc;
}data_t;
data_tdata5={
.a=0X11223344,
.b=0X55667788,
.c=0X99AABBCC,
};

uint8_tdata[100];
staticuint8_ts_hwQueueBuffer[100];
staticbyte_queue_tmy_queue;

queue_init(&my_queue,s_hwQueueBuffer,sizeof(s_hwQueueBuffer));
//根據變量的類型,自動計算對象的大小
enqueue(&my_queue,data1);
enqueue(&my_queue,data2);
enqueue(&my_queue,data3);

//一下三種方式都可以正確存儲數組
enqueue(&my_queue,data4,2);//可以不指名數據類型
enqueue(&my_queue,data4,uint16_t,2);//也可以指名數據類型
enqueue(&my_queue,data4,uint8_t,sizeof(data4));//或者用其他類型

//一下兩種方式都可以正確存儲結構體類型
enqueue(&my_queue,data5);//根據結構體的類型,自動計算對象的大小
enqueue(&my_queue,&data5,uint8_t,sizeof(data5));//也可以以數組方式存儲

enqueue(&my_queue,(uint8_t)0X11);//常量默認為int型,需要強制轉換數據類型
enqueue(&my_queue,(uint16_t)0X2233);//常量默認為int型,需要強制轉換數據類型
enqueue(&my_queue,0X44556677);
enqueue(&my_queue,(char)'a');//單個字符也需要強制轉換數據類型
enqueue(&my_queue,"bc");//字符串默認會存儲空字符\0
enqueue(&my_queue,"def");

//讀出全部數據
dequeue(&my_queue,data,get_queue_count(&my_queue));

結語

本文的目的,告訴大家如何正確的看待宏——宏不是阻礙代碼開發和可讀性的魔鬼

宏不是奇技淫巧

宏可以封裝出其它高級語言所提供的“基礎設施”

設計良好的宏可以提升代碼的可讀性,而不是破壞它

設計良好的宏并不會影響調試

宏可以用來固化某些模板,避免每次都重新編寫復雜的語法結構

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式系統
    +關注

    關注

    41

    文章

    3593

    瀏覽量

    129473
  • 函數
    +關注

    關注

    3

    文章

    4331

    瀏覽量

    62618
  • 數據結構
    +關注

    關注

    3

    文章

    573

    瀏覽量

    40130
收藏 人收藏

    評論

    相關推薦

    C++重載運算符和重載函數詳解

    在計算機程序設計中,運算符重載(英語:operator overloading)是多態的一種。這里,運算符(比如+,=或==)被當作多態函數,它們的行為隨著其參數類型的不同而不同。運算符并不一定總是符號。
    發表于 09-20 17:14 ?1979次閱讀

    線程編程之二 MFC中的線開發

    線程編程之二 MFC中的線開發五、MFC對多線程編程的支持  MFC中有兩類線程,分別稱之為工作者
    發表于 10-22 11:42

    關于C++中的函數重載機制

    重載機制是一種"假的"多態.(因為他是在編譯階段就進行分配的機制).另外,C++中還有一種"假的"多態機制就是模板機制,同樣只是改變函數參數的類型,并不會改變函數具體的實現方式.
    發表于 10-01 17:18

    函數重載隱藏覆蓋的區別

    參數類型不同,或者參數個數和參數類型都不同),返回值類型可相同也可不同;這種情況叫做c++的重載!注意:c語言沒有函數
    發表于 05-11 09:33

    TWEN-ASR ONE 語音識別系列教程(4)---多線程與消息隊列使用

    TWEN-ASR ONE 語音識別系列教程(4)—多線程與消息隊列使用提示:作者使用 TWEN-ASR ONE V1.0開發板進行開發學習。文章目錄前言一、多線程的使用與測試1.1線程
    發表于 07-02 16:27

    printf()h函數重載后還需要加入修改項函數重載

    printf()h函數重載后,還需要加入下圖的修改項函數重載時,在自定義頭文件中包含 stdio.h 文件,并加入以下重載
    發表于 08-23 09:33

    RT-Thread系統消息隊列常用的函數接口有哪些

    ,等待消息隊列線程按照優先級的方式進行排列。2. 發送消息RT-Thread 提供的發送消息接口函數有兩種:一種是無等待超時接口,一種是有等待超時。線程或者中斷服務程序都可以給消息
    發表于 03-31 14:14

    嵌入式-C++函數重載

    一、什么是函數重載 兩個以上的函數,具有相同的函數名,通過參數的類型和參數的個數不同。編譯器自行匹配,自動確定調用哪一個
    發表于 06-28 13:54

    隊列FIFO——支持網絡QoS的重要芯片

    摘要:在IP網絡中支持QoS是近年來研究的熱點,而IDT公司推出的新型存儲器件——隊列FIFO能夠支持QoS的應用。因其具有單器件下支持
    發表于 03-11 13:22 ?1163次閱讀
    <b class='flag-5'>多</b><b class='flag-5'>隊列</b>FIFO——<b class='flag-5'>支持</b>網絡QoS的重要芯片

    線程安全隊列技術在交流電機調速系統中的應用

    介紹了數據保護的概念和原理,根據交流電機調速系統的要求,使用線程安全隊列技術對電機的數據進行保護,以期能正確反映電機的運行情況.通過實驗,對使用線程安全隊列技術的
    發表于 05-25 15:26 ?46次下載
    <b class='flag-5'>線程</b><b class='flag-5'>安全隊列</b>技術在交流電機調速系統中的應用

    什么是線程安全

    線程安全的鏈表-隊列-棧,就是多線程同時操作(包括查找、添加、刪除等)鏈表、隊列或棧,無論如何操作,就是多
    發表于 11-17 11:16 ?1次下載

    C++之類中的函數重載學習的總結

    類的成員函數之間可以進行重載重載必須發生在同一個作用域中;全局函數和成員函數不能構成重載關系;
    的頭像 發表于 12-24 17:02 ?512次閱讀

    uC/OS-II隊列原理 隊列相關函數介紹

    消息隊列線程間通訊的一種,主要用作數據緩沖,用途非常廣泛。一般情況下遵循先進先出原則。
    的頭像 發表于 09-11 15:04 ?941次閱讀
    uC/OS-II<b class='flag-5'>隊列</b>原理 <b class='flag-5'>隊列</b>相關<b class='flag-5'>函數</b>介紹

    如何實現一個寫的線程安全的無鎖隊列

    加鎖。那么如何實現一個寫的線程安全的無鎖隊列呢? 互斥鎖:mutexqueue(太簡單不介紹了) 互斥鎖+條件變量:blockqueu
    的頭像 發表于 11-08 15:25 ?1317次閱讀
    如何實現一個<b class='flag-5'>多</b>讀<b class='flag-5'>多</b>寫的<b class='flag-5'>線程</b><b class='flag-5'>安全</b>的無鎖<b class='flag-5'>隊列</b>

    探索虛擬線程:原理與實現

    虛擬線程的引入與優勢 在Loom項目之前,Java虛擬機(JVM)中的線程是通過java.lang.Thread類型來實現的,這些線程被稱為平臺線程
    的頭像 發表于 06-24 11:35 ?306次閱讀
    <b class='flag-5'>探索</b>虛擬<b class='flag-5'>線程</b>:原理與實現
    主站蜘蛛池模板: 午夜一区二区在线观看| 久久啊| you ji z z日本人在线观看| 欧美极品色影院| 日韩毛片免费看| 午夜在线视频免费观看| 看黄视频网站| 色婷婷免费视频| 97综合| 免费被黄网站在观看| 神马电影天堂网| 夜夜爱夜夜操| 444kk免费| 全黄性色大片| 天天操穴| 国产精品免费久久久免费| 免费黄色国产视频| 久久天天躁夜夜躁狠狠85麻豆 | 男人的天堂天堂网| 日日搞夜夜操| 一级毛片一级黄片| 国产精品毛片久久久久久久| 成人夜色香网站在线观看| 网站色小妹| 午夜影院免费入口| 欧美视频三区| 国模伊人| 欧美xxxx性疯狂bbbb| 日本黄色免费在线观看| 天天操天天草| 亚洲特黄大黄一级毛片| 成人性生活免费视频| 2022年永久免费观看| 免费网站毛片| 爱爱天堂| 欧美午夜性| 国产午夜精品久久久久| 色综合婷婷| 人人干人人舔| 他也色在线| 日日操狠狠操|