本發(fā)明涉及一種多線程數(shù)據(jù)傳輸方法,特別是涉及一種適用于多線程通信中,多線程訪問的多線程數(shù)據(jù)傳輸方法。
背景技術(shù):
一般在多線程通信中,會存在一些對臨界資源(多個線程都可能同時被訪問)的訪問,因臨界資源是公共的,如果同時被多個線程讀寫的時候,臨界資源會成為一種未知狀態(tài),是不安全的,會導致程序產(chǎn)生莫名的錯誤,所以程序在使用臨界資源時往往會通過線程鎖來保證臨界資源的訪問是安全可控,通過線程鎖來保證有任意時刻只有會一個線程來操作臨界資源;但是這種機制會導致其它線程處理等待狀態(tài),從而降低系統(tǒng)處理性能。
技術(shù)實現(xiàn)要素:
本發(fā)明要解決的技術(shù)問題是提供一種多線程數(shù)據(jù)傳輸方法,能夠解決兩線程之間數(shù)據(jù)傳輸,即對隊列容器這個臨界資源實現(xiàn)無鎖化的訪問,極大提高性能。
本發(fā)明采用的技術(shù)方案如下:一種多線程數(shù)據(jù)傳輸方法,具體方法為:
初始化系統(tǒng)時,申請一個能夠容納N個指針的連續(xù)內(nèi)存空間;所述N=2m,m為大于等于1的整數(shù);每個指針位置為一個單位,N個指針位置組成一個數(shù)組空間dataPtrArray;所述指針指向用戶數(shù)據(jù)地址;
定義兩個整數(shù)值:writePos和readPos;其中,writePos表示數(shù)據(jù)寫入線程當前正要寫入所述數(shù)組空間的位置;readPos表示數(shù)據(jù)讀取線程當前正要從所述數(shù)組空間讀取數(shù)據(jù)的位置;數(shù)據(jù)寫入成功,則writePos值自增;數(shù)據(jù)讀取成功,則readPos值自增,將被成功讀取的數(shù)組空間位置的指針值清零,清零后,寫入線程再發(fā)現(xiàn)這個位置是零,才能夠正常寫入新的用戶指針數(shù)據(jù);
當dataPtrArray寫滿數(shù)據(jù)但是并未被及時讀取走時,會寫入失敗;當dataPtrArray中所有值都為零時,會讀取失?。?/p>
定義一個整數(shù)掩碼PosMask,其值為N-1;通過PosMask的值與讀寫位置的值做與運算,來決定當前正要寫入和讀取的真正的數(shù)組空間的位置,即當前寫入的位置應該是dataPtrArray[writePos&PosMask],讀取的位置是dataPtrArray[readPos&PosMask]。
申明成連續(xù)的內(nèi)存數(shù)組,能夠快速的通過數(shù)組的單位序列值快速的讀取和寫入數(shù)據(jù)指針;但是當數(shù)據(jù)寫入和讀取到數(shù)組尾部時,勢必要通過程序的判斷,并且此判斷在多線程中會引起性能開銷,固本發(fā)明使用了一種能夠無性能開銷,并且數(shù)據(jù)在讀取和寫入數(shù)據(jù)尾部數(shù)據(jù)后,直接跳到數(shù)據(jù)首部;通過PosMask的值與讀寫位置的值做與運算,來決定當前正要寫入和讀取的真正在數(shù)據(jù)組空間的位置數(shù)據(jù)指針在dataPtrArray讀取實現(xiàn)了尾頭相接,且無任何開鎖,具有極高的性能。
所述方法還包括:寫入數(shù)據(jù)時,采用Intel的鎖總線技術(shù),以原子的方式,同時判斷寫入位置是否為空,若為空,則寫入,若不為空,則表示隊列已經(jīng)寫滿了,此時寫入線程陷入等待;讀取數(shù)據(jù)時,采用Intel的鎖總線技術(shù),以原子方式的判斷讀取位置是否為空,若不為空,則讀取返回,并且將讀取位置清零,若為空,則表示整個隊列都已經(jīng)讀取完,此時讀取線程陷入等待;當成功的寫入一個數(shù)據(jù)指針時通知讀取線程數(shù)據(jù)可讀取,此時,如果讀取線程為休眠狀態(tài),則將被喚醒;當成功的讀取一個數(shù)據(jù)指針時通知寫入線程數(shù)據(jù)可寫入,此時,如果寫入線程為休眠狀態(tài),則將被喚醒。
因為讀取和寫入線程是異步的,所以readPos和writePos可能存在重疊的情況(即當數(shù)據(jù)空間被寫滿或者為空時),此時讀取和寫入是同一個位置,即是一個臨界區(qū),這種情況必須使數(shù)據(jù)得到保護,相較傳統(tǒng)的線程鎖具有很高的代價,本方法以一種性能極高的方式實現(xiàn)了臨界區(qū)的高效讀寫。
所述內(nèi)存空間中,以每8個字節(jié)為一個單位。內(nèi)存空間以8個字節(jié),即一個uint64_t為一個單位,可以存放任意系統(tǒng)下的sizeof(void*)的值,即存儲一個指針的值(一個指針最長為一個uint64_t)。
與現(xiàn)有技術(shù)相比,本發(fā)明的有益效果是:能夠解決兩線程之間數(shù)據(jù)傳輸,即對隊列容器這個臨界資源實現(xiàn)無鎖化的訪問,極大提高性能;以一種性能極高的方式實現(xiàn)了臨界區(qū)的高效讀寫。
具體實施方式
為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點更加清楚明白,以下結(jié)合實施例,對本發(fā)明進行進一步詳細說明。應當理解,此處所描述的具體實施例僅用以解釋本發(fā)明,并不用于限定本發(fā)明。
本說明書(包括摘要)中公開的任一特征,除非特別敘述,均可被其他等效或者具有類似目的的替代特征加以替換。即,除非特別敘述,每個特征只是一系列等效或類似特征中的一個例子而已。
具體實施例1
一種多線程數(shù)據(jù)傳輸方法,具體方法為:
初始化系統(tǒng)時,申請一個能夠容納N個指針的連續(xù)內(nèi)存空間;所述N=2m,m為大于等于1的整數(shù);每個指針位置為一個單位,N個指針位置組成一個數(shù)組空間dataPtrArray;所述指針指向用戶數(shù)據(jù)地址;
定義兩個整數(shù)值:writePos和readPos;其中,writePos表示數(shù)據(jù)寫入線程當前正要寫入所述數(shù)組空間的位置;readPos表示數(shù)據(jù)讀取線程當前正要從所述數(shù)組空間讀取數(shù)據(jù)的位置;數(shù)據(jù)寫入成功,則writePos值自增;數(shù)據(jù)讀取成功,則readPos值自增,將被成功讀取的數(shù)組空間位置的指針值清零,清零后,寫入線程再發(fā)現(xiàn)這個位置是零,才能夠正常寫入新的用戶指針數(shù)據(jù);
當dataPtrArray寫滿數(shù)據(jù)但是并未被及時讀取走時,會寫入失?。划攄ataPtrArray中所有值都為零時,會讀取失敗;
定義一個整數(shù)掩碼PosMask,其值為N-1;通過PosMask的值與讀寫位置的值做與運算,來決定當前正要寫入和讀取的真正的數(shù)組空間的位置,即當前寫入的位置應該是dataPtrArray[writePos&PosMask],讀取的位置是dataPtrArray[readPos&PosMask]。
具體實施例2
在具體實施例1的基礎(chǔ)上,所述方法還包括:寫入數(shù)據(jù)時,采用Intel的鎖總線技術(shù),以原子的方式,同時判斷寫入位置是否為空,若為空,則寫入,若不為空,則表示隊列已經(jīng)寫滿了,此時寫入線程陷入等待:
void* dataPtr是一個需要被寫入隊列的數(shù)據(jù)指針,
do{
uint32_t writeLocation = _sync_fetch_and_add(&writePos,1);
uint64_t* writePtr = (uint64_t*)dataPtrArray[PosMask&writeLocation];
if(__sync_bool_compare_and_swap(writePtr,0,(uint64_t)dataPtr))
{
notifyRead();
return true; //寫入成功
}
else
{
wait();
}
}
讀取數(shù)據(jù)時,采用Intel的鎖總線技術(shù),以原子方式的判斷讀取位置是否為空,若不為空,則讀取返回,并且將讀取位置清零,若為空,則表示整個隊列都已經(jīng)讀取完,此時讀取線程陷入等待:
uint64_t readPtrValue = 0,是從隊列中讀取的值,被返回給使用者,
uint32_t readLocaltion = __sync_fetch_and_add(&readPos,1);
uint64_t* readPtr = (uint64_t*)dataPtrArray[PosMask&readLocaltion];
if((readPtrValue =__sync_lock_test_and_set(readPtr,0)) != 0 )
{
notifyWrite();
return readPtrValue; //讀取成功
}
else
{
wait();
}
當成功的寫入一個數(shù)據(jù)指針時通知讀取線程數(shù)據(jù)可讀取,此時,如果讀取線程為休眠狀態(tài),則將被喚醒;當成功的讀取一個數(shù)據(jù)指針時通知寫入線程數(shù)據(jù)可寫入,此時,如果寫入線程為休眠狀態(tài),則將被喚醒。
具體實施例3
在具體實施例1或2的基礎(chǔ)上,所述內(nèi)存空間中,以每8個字節(jié)為一個單位。內(nèi)存空間以8個字節(jié),即一個uint64_t為一個單位,可以存放任意系統(tǒng)下的sizeof(void*)的值,即存儲一個指針的值(一個指針最長為一個uint64_t)。