| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526 |
- /*
- * Copyright: JessMA Open Source (ldcsaa@gmail.com)
- *
- * Version : 2.3.18
- * Author : Bruce Liang
- * Website : http://www.jessma.org
- * Project : https://github.com/ldcsaa
- * Blog : http://www.cnblogs.com/ldcsaa
- * Wiki : http://www.oschina.net/p/hp-socket
- * QQ Group : 75375912
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- #pragma once
- #include "STLHelper.h"
- #include "RWLock.h"
- #include "CriticalSection.h"
- #define CACHE_LINE 64
- #define PACK_SIZE_OF(T) (CACHE_LINE - sizeof(T) % CACHE_LINE)
- #if !defined (_WIN64)
- #pragma pack(push, 4)
- #endif
- template <class T, class _PutGuard = CCriSec, class _GetGuard = CCriSec> class CRingBuffer
- {
- public:
- static const UINT DEFAULT_EXPECT = 4096;
- public:
- BOOL Put(T* pElement)
- {
- ASSERT(pElement != nullptr);
- {
- CLocalLock<_PutGuard> locallock(m_csPut);
- ULONGLONG seqPut = m_seqPut;
- WaitForPut(seqPut);
- if(!IsValid()) return FALSE;
- DoPut(pElement, seqPut);
- }
- return TRUE;
- }
- BOOL TryPut(T* pElement)
- {
- ASSERT(pElement != nullptr);
- if(!IsValid() || !HasPutSpace(m_seqPut))
- return FALSE;
- {
- CLocalLock<_PutGuard> locallock(m_csPut);
- ULONGLONG seqPut = m_seqPut;
- if(!IsValid() || !HasPutSpace(seqPut))
- return FALSE;
- DoPut(pElement, seqPut);
- }
- return TRUE;
- }
- BOOL PutBatch(T* pElements[], int& iCount)
- {
- ASSERT(pElements != nullptr && iCount > 0);
- {
- CLocalLock<_PutGuard> locallock(m_csPut);
- ULONGLONG seqPut = m_seqPut;
- for(int i = 0; i < iCount; ++i)
- {
- WaitForPut(seqPut);
- if(!IsValid())
- {
- iCount = i;
- return FALSE;
- }
- DoPut(*(pElements + i), seqPut);
- }
- }
- return TRUE;
- }
- BOOL TryPutBatch(T* pElements[], int& iCount)
- {
- ASSERT(pElements != nullptr && iCount > 0);
- if(!IsValid() || !HasPutSpace(m_seqPut))
- {
- iCount = 0;
- return FALSE;
- }
- {
- CLocalLock<_PutGuard> locallock(m_csPut);
- ULONGLONG seqPut = m_seqPut;
- for(int i = 0; i < iCount; ++i)
- {
- if(!IsValid() || !HasPutSpace(seqPut))
- {
- iCount = i;
- return FALSE;
- }
- DoPut(*(pElements + i), seqPut);
- }
- }
- return TRUE;
- }
- BOOL Get(T** pElement)
- {
- ASSERT(pElement != nullptr);
- {
- CLocalLock<_GetGuard> locallock(m_csGet);
- ULONGLONG seqGet = m_seqGet;
- WaitForGet(seqGet);
- if(!IsValid()) return FALSE;
- DoGet(pElement, seqGet);
- }
- return TRUE;
- }
- BOOL TryGet(T** pElement)
- {
- ASSERT(pElement != nullptr);
- if(!IsValid() || !HasGetSpace(m_seqGet))
- return FALSE;
- {
- CLocalLock<_GetGuard> locallock(m_csGet);
- ULONGLONG seqGet = m_seqGet;
- if(!IsValid() || !HasGetSpace(seqGet))
- return FALSE;
- DoGet(pElement, seqGet);
- }
- return TRUE;
- }
- BOOL GetBatch(T* pElements[], int& iCount)
- {
- ASSERT(pElements != nullptr && iCount > 0);
- {
- CLocalLock<_GetGuard> locallock(m_csGet);
- ULONGLONG seqGet = m_seqGet;
- for(int i = 0; i < iCount; ++i)
- {
- WaitForGet(seqGet);
- if(!IsValid())
- {
- iCount = i;
- return FALSE;
- }
- DoGet(pElements + i, seqGet);
- }
- }
- return TRUE;
- }
- BOOL TryGetBatch(T* pElements[], int& iCount)
- {
- ASSERT(pElements != nullptr && iCount > 0);
- if(!IsValid() || !HasGetSpace(m_seqGet))
- {
- iCount = 0;
- return FALSE;
- }
- {
- CLocalLock<_GetGuard> locallock(m_csGet);
- ULONGLONG seqGet = m_seqGet;
- for(int i = 0; i < iCount; ++i)
- {
- if(!IsValid() || !HasGetSpace(seqGet))
- {
- iCount = i;
- return FALSE;
- }
- DoGet(pElements + i, seqGet);
- }
- }
- return TRUE;
- }
- BOOL Peek(T** pElement)
- {
- ASSERT(pElement != nullptr);
- ULONGLONG seqGet = m_seqGet;
- if(!IsValid() || !HasGetSpace(seqGet))
- return FALSE;
- DoPeek(pElement, seqGet);
- return TRUE;
- }
- private:
- void DoPut(T* pElement, ULONGLONG& seqPut)
- {
- DWORD index = seqPut & (m_dwReal - 1);
- *(m_pv + index) = pElement;
- ++seqPut;
- m_seqPut = seqPut;
- }
- void DoGet(T** pElement, ULONGLONG& seqGet)
- {
- DWORD index = seqGet & (m_dwReal - 1);
- *(pElement) = *(m_pv + index);
- ++seqGet;
- m_seqGet = seqGet;
- }
- void DoPeek(T** pElement, ULONGLONG& seqGet)
- {
- DWORD index = seqGet & (m_dwReal - 1);
- *(pElement) = *(m_pv + index);
- }
- BOOL HasPutSpace(ULONGLONG seqPut)
- {
- return (seqPut - m_seqGet < m_dwReal);
- }
- void WaitForPut(ULONGLONG seqPut)
- {
- for(DWORD w = 0; IsValid(); ++w)
- {
- if(HasPutSpace(seqPut))
- break;
- ::YieldThread(w);
- }
- }
- BOOL HasGetSpace(ULONGLONG seqGet)
- {
- return (m_seqPut - seqGet > 0);
- }
- void WaitForGet(ULONGLONG seqGet)
- {
- for(DWORD w = 0; IsValid(); ++w)
- {
- if(HasGetSpace(seqGet))
- break;
- ::YieldThread(w);
- }
- }
- DWORD Revise(DWORD dwExpect)
- {
- int index = 0;
- int shift = sizeof(DWORD) * 8 - 1;
- for(int i = shift; i >= 0; i--)
- {
- if(index == 0)
- {
- if(dwExpect & (1 << i))
- {
- index = i;
- if(index == shift)
- break;
- }
- }
- else
- {
- if(dwExpect & (1 << i))
- ++index;
- break;
- }
- }
- return 1 << index;
- }
- public:
- CRingBuffer(DWORD uiExpect = DEFAULT_EXPECT)
- : m_pv(nullptr)
- , m_dwReal(0)
- , m_seqPut(0)
- , m_seqGet(0)
- {
- Reset(uiExpect);
- }
- ~CRingBuffer()
- {
- Reset(0);
- }
- void Reset(DWORD uiExpect = DEFAULT_EXPECT)
- {
- if(IsValid())
- Destroy();
- if(uiExpect > 0)
- Create(uiExpect);
- }
- BOOL IsValid() {return m_pv != nullptr;}
- private:
- void Create(DWORD dwExpect = DEFAULT_EXPECT)
- {
- ASSERT(!IsValid() && dwExpect > 0);
- m_seqPut = 0;
- m_seqGet = 0;
- m_dwReal = Revise(dwExpect);
- m_pv = (T**)malloc(m_dwReal * sizeof(T*));
- }
- void Destroy()
- {
- ASSERT(IsValid());
- CLocalLock<_PutGuard> locallock1(m_csPut);
- CLocalLock<_GetGuard> locallock2(m_csGet);
- free((void*)m_pv);
- m_pv = nullptr;
- m_dwReal = 0;
- m_seqPut = 0;
- m_seqGet = 0;
- }
- private:
- CRingBuffer(const CRingBuffer&);
- CRingBuffer operator = (const CRingBuffer&);
- private:
- DWORD m_dwReal;
- T** m_pv;
- char pack1[PACK_SIZE_OF(T**)];
- volatile ULONGLONG m_seqPut;
- char pack4[PACK_SIZE_OF(ULONGLONG)];
- volatile ULONGLONG m_seqGet;
- char pack5[PACK_SIZE_OF(ULONGLONG)];
- _PutGuard m_csPut;
- char pack2[PACK_SIZE_OF(_PutGuard)];
- _GetGuard m_csGet;
- char pack3[PACK_SIZE_OF(_GetGuard)];
- };
- typedef CRingBuffer<void, CCriSec, CCriSec> CCSRingBuffer;
- typedef CRingBuffer<void, CInterCriSec, CInterCriSec> CICSRingBuffer;
- typedef CRingBuffer<void, CSpinGuard, CSpinGuard> CSGRingBuffer;
- typedef CRingBuffer<void, CFakeGuard, CFakeGuard> CFKRingBuffer;
- // ------------------------------------------------------------------------------------------------------------- //
- template <class T, class index_type = DWORD, bool adjust_index = false> class CRingCache
- {
- public:
- enum EnGetResult {GR_FAIL = -1, GR_INVALID = 0, GR_VALID = 1};
- typedef T* TPTR;
- typedef volatile T* VTPTR;
- typedef unordered_set<index_type> IndexSet;
- typedef typename IndexSet::const_iterator IndexSetCI;
- typedef typename IndexSet::iterator IndexSetI;
- static TPTR const E_EMPTY;
- static TPTR const E_LOCKED;
- static TPTR const E_MAX_STATUS;
- public:
- static index_type& INDEX_INC(index_type& dwIndex) {if(adjust_index) ++dwIndex; return dwIndex;}
- static index_type& INDEX_DEC(index_type& dwIndex) {if(adjust_index) --dwIndex; return dwIndex;}
- private:
- VTPTR& INDEX_VAL(index_type dwIndex) {return *(m_pv + dwIndex);}
- public:
- BOOL Put(TPTR pElement, index_type& dwIndex)
- {
- ASSERT(pElement != nullptr);
- if(!IsValid()) return FALSE;
- BOOL isOK = FALSE;
- while(true)
- {
- if(!HasSpace())
- break;
- DWORD dwCurSeq = m_dwCurSeq;
- index_type dwCurIndex = dwCurSeq % m_dwSize;
- VTPTR& pValue = INDEX_VAL(dwCurIndex);
- if(pValue == E_EMPTY)
- {
- if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, pElement, E_EMPTY) == E_EMPTY)
- {
- ::InterlockedIncrement(&m_dwCount);
- ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
- dwIndex = INDEX_INC(dwCurIndex);
- isOK = TRUE;
- if(pElement != E_LOCKED)
- EmplaceIndex(dwIndex);
- break;
- }
- }
- ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
- }
- return isOK;
- }
- EnGetResult Get(index_type dwIndex, TPTR* ppElement)
- {
- ASSERT(dwIndex <= m_dwSize);
- ASSERT(ppElement != nullptr);
- if(!IsValid() || INDEX_DEC(dwIndex) >= m_dwSize)
- {
- *ppElement = nullptr;
- return GR_FAIL;
- }
- *ppElement = (TPTR)INDEX_VAL(dwIndex);
- return IsValidElement(*ppElement) ? GR_VALID : GR_INVALID;
- }
- BOOL Set(index_type dwIndex, TPTR pElement, TPTR* ppOldElement = nullptr)
- {
- TPTR pElement2 = nullptr;
- if(Get(dwIndex, &pElement2) == GR_FAIL)
- return FALSE;
- if(ppOldElement != nullptr)
- *ppOldElement = pElement2;
- if(pElement == pElement2)
- return FALSE;
- int f1 = 0;
- int f2 = 0;
- if(pElement == E_EMPTY)
- {
- if(pElement2 == E_LOCKED)
- f1 = -1;
- else
- f1 = f2 = -1;
- }
- else if(pElement == E_LOCKED)
- {
- if(pElement2 == E_EMPTY)
- f1 = 1;
- else
- f2 = -1;
- }
- else
- {
- if(pElement2 == E_EMPTY)
- f1 = f2 = 1;
- else if(pElement2 == E_LOCKED)
- f2 = 1;
- }
- BOOL bSetValueFirst = (f1 + f2 >= 0);
- index_type dwOuterIndex = dwIndex;
- INDEX_DEC(dwIndex);
- if(bSetValueFirst) INDEX_VAL(dwIndex) = pElement;
- if(f1 > 0) ::InterlockedIncrement(&m_dwCount);
- if(f2 != 0) (f2 > 0) ? EmplaceIndex(dwOuterIndex) : EraseIndex(dwOuterIndex);
- if(f1 < 0) ::InterlockedDecrement(&m_dwCount);
- if(!bSetValueFirst) INDEX_VAL(dwIndex) = pElement;
- ASSERT(Spaces() <= Size());
- return TRUE;
- }
- BOOL Remove(index_type dwIndex, TPTR* ppElement = nullptr)
- {
- return Set(dwIndex, E_EMPTY, ppElement);
- }
- BOOL AcquireLock(index_type& dwIndex)
- {
- return Put(E_LOCKED, dwIndex);
- }
- BOOL ReleaseLock(index_type dwIndex, TPTR pElement)
- {
- ASSERT(pElement == nullptr || IsValidElement(pElement));
- TPTR pElement2 = nullptr;
- Get(dwIndex, &pElement2);
- ASSERT(pElement2 == E_LOCKED);
- if(pElement2 != E_LOCKED)
- return FALSE;
- return Set(dwIndex, pElement);
- }
- public:
- void Reset(DWORD dwSize = 0)
- {
- if(IsValid())
- Destroy();
- if(dwSize > 0)
- Create(dwSize);
- }
-
- BOOL GetAllElementIndexes(index_type ids[], DWORD& dwCount, BOOL bCopy = TRUE)
- {
- if(ids == nullptr || dwCount == 0)
- {
- dwCount = Elements();
- return FALSE;
- }
- IndexSet* pIndexes = nullptr;
- IndexSet indexes;
- if(bCopy)
- pIndexes = &CopyIndexes(indexes);
- else
- pIndexes = &m_indexes;
- BOOL isOK = FALSE;
- DWORD dwSize = (DWORD)pIndexes->size();
- if(dwSize > 0 && dwSize <= dwCount)
- {
- IndexSetCI it = pIndexes->begin();
- IndexSetCI end = pIndexes->end();
- for(int i = 0; it != end; ++it, ++i)
- ids[i] = *it;
- isOK = TRUE;
- }
- dwCount = dwSize;
- return isOK;
- }
-
- unique_ptr<index_type[]> GetAllElementIndexes(DWORD& dwCount, BOOL bCopy = TRUE)
- {
- IndexSet* pIndexes = nullptr;
- IndexSet indexes;
- if(bCopy)
- pIndexes = &CopyIndexes(indexes);
- else
- pIndexes = &m_indexes;
- unique_ptr<index_type[]> ids;
- dwCount = (DWORD)pIndexes->size();
- if(dwCount > 0)
- {
- ids.reset(new index_type[dwCount]);
- IndexSetCI it = pIndexes->begin();
- IndexSetCI end = pIndexes->end();
- for(int i = 0; it != end; ++it, ++i)
- ids[i] = *it;
- }
- return ids;
- }
- static BOOL IsValidElement(TPTR pElement) {return pElement > E_MAX_STATUS;}
- DWORD Size () {return m_dwSize;}
- DWORD Elements () {return (DWORD)m_indexes.size();}
- DWORD Spaces () {return m_dwSize - m_dwCount;}
- BOOL HasSpace () {return m_dwCount < m_dwSize;}
- BOOL IsEmpty () {return m_dwCount == 0;}
- BOOL IsValid () {return m_pv != nullptr;}
- private:
- void Create(DWORD dwSize)
- {
- ASSERT(!IsValid() && dwSize > 0);
- m_dwCurSeq = 0;
- m_dwCount = 0;
- m_dwSize = dwSize;
- m_pv = (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
- ::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
- }
- void Destroy()
- {
- ASSERT(IsValid());
- m_indexes.clear();
- free((void*)m_pv);
- m_pv = nullptr;
- m_dwSize = 0;
- m_dwCount = 0;
- m_dwCurSeq = 0;
- }
- IndexSet& CopyIndexes(IndexSet& indexes)
- {
- {
- CReadLock locallock(m_cs);
- indexes = m_indexes;
- }
- return indexes;
- }
- void EmplaceIndex(index_type dwIndex)
- {
- CWriteLock locallock(m_cs);
- m_indexes.emplace(dwIndex);
- }
- void EraseIndex(index_type dwIndex)
- {
- CWriteLock locallock(m_cs);
- m_indexes.erase(dwIndex);
- }
- public:
- CRingCache (DWORD dwSize = 0)
- : m_pv (nullptr)
- , m_dwSize (0)
- , m_dwCount (0)
- , m_dwCurSeq(0)
- {
- Reset(dwSize);
- }
- ~CRingCache()
- {
- Reset(0);
- }
- private:
- CRingCache(const CRingCache&);
- CRingCache operator = (const CRingCache&);
- private:
- DWORD m_dwSize;
- VTPTR* m_pv;
- char pack1[PACK_SIZE_OF(VTPTR*)];
- volatile DWORD m_dwCurSeq;
- char pack2[PACK_SIZE_OF(DWORD)];
- volatile DWORD m_dwCount;
- char pack3[PACK_SIZE_OF(DWORD)];
- CSimpleRWLock m_cs;
- IndexSet m_indexes;
- };
- template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_EMPTY = (T*)0x00;
- template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_LOCKED = (T*)0x01;
- template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_MAX_STATUS = (T*)0x0F;
- // ------------------------------------------------------------------------------------------------------------- //
- template <class T, class index_type = DWORD, bool adjust_index = false> class CRingCache2
- {
- public:
- enum EnGetResult {GR_FAIL = -1, GR_INVALID = 0, GR_VALID = 1};
- typedef T* TPTR;
- typedef volatile T* VTPTR;
- typedef unordered_set<index_type> IndexSet;
- typedef typename IndexSet::const_iterator IndexSetCI;
- typedef typename IndexSet::iterator IndexSetI;
- static TPTR const E_EMPTY;
- static TPTR const E_LOCKED;
- static TPTR const E_MAX_STATUS;
- static DWORD const MAX_SIZE;
- public:
- static index_type& INDEX_INC(index_type& dwIndex) {if(adjust_index) ++dwIndex; return dwIndex;}
- static index_type& INDEX_DEC(index_type& dwIndex) {if(adjust_index) --dwIndex; return dwIndex;}
- index_type& INDEX_R2V(index_type& dwIndex) {dwIndex += *(m_px + dwIndex) * m_dwSize; return dwIndex;}
- BOOL INDEX_V2R(index_type& dwIndex)
- {
- index_type m = dwIndex % m_dwSize;
- BYTE x = *(m_px + m);
- if(dwIndex / m_dwSize != x)
- return FALSE;
- dwIndex = m;
- return TRUE;
- }
- private:
- VTPTR& INDEX_VAL(index_type dwIndex) {return *(m_pv + dwIndex);}
- public:
- BOOL Put(TPTR pElement, index_type& dwIndex)
- {
- ASSERT(pElement != nullptr);
- if(!IsValid()) return FALSE;
- BOOL isOK = FALSE;
- while(true)
- {
- if(!HasSpace())
- break;
- DWORD dwCurSeq = m_dwCurSeq;
- index_type dwCurIndex = dwCurSeq % m_dwSize;
- VTPTR& pValue = INDEX_VAL(dwCurIndex);
- if(pValue == E_EMPTY)
- {
- if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, pElement, E_EMPTY) == E_EMPTY)
- {
- ::InterlockedIncrement(&m_dwCount);
- ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
- dwIndex = INDEX_INC(INDEX_R2V(dwCurIndex));
- isOK = TRUE;
- if(pElement != E_LOCKED)
- EmplaceIndex(dwIndex);
- break;
- }
- }
- ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
- }
- return isOK;
- }
- EnGetResult Get(index_type dwIndex, TPTR* ppElement, index_type* pdwRealIndex = nullptr)
- {
- ASSERT(ppElement != nullptr);
- if(!IsValid() || !INDEX_V2R(INDEX_DEC(dwIndex)))
- {
- *ppElement = nullptr;
- return GR_FAIL;
- }
- *ppElement = (TPTR)INDEX_VAL(dwIndex);
- if(pdwRealIndex) *pdwRealIndex = dwIndex;
- return IsValidElement(*ppElement) ? GR_VALID : GR_INVALID;
- }
- BOOL Set(index_type dwIndex, TPTR pElement, TPTR* ppOldElement = nullptr, index_type* pdwRealIndex = nullptr)
- {
- TPTR pElement2 = nullptr;
- if(pdwRealIndex == nullptr)
- pdwRealIndex = (index_type*)_alloca(sizeof(index_type));
- if(Get(dwIndex, &pElement2, pdwRealIndex) == GR_FAIL)
- return FALSE;
- if(ppOldElement != nullptr)
- *ppOldElement = pElement2;
- if(pElement == pElement2)
- return FALSE;
- int f1 = 0;
- int f2 = 0;
- if(pElement == E_EMPTY)
- {
- if(pElement2 == E_LOCKED)
- f1 = -1;
- else
- f1 = f2 = -1;
- }
- else if(pElement == E_LOCKED)
- {
- if(pElement2 == E_EMPTY)
- f1 = 1;
- else
- f2 = -1;
- }
- else
- {
- if(pElement2 == E_EMPTY)
- f1 = f2 = 1;
- else if(pElement2 == E_LOCKED)
- f2 = 1;
- }
- BOOL bSetValueFirst = (f1 + f2 >= 0);
- index_type dwRealIndex = *pdwRealIndex;
- if(bSetValueFirst) INDEX_VAL(dwRealIndex) = pElement;
- if(f1 > 0) ::InterlockedIncrement(&m_dwCount);
- if(f2 != 0) (f2 > 0) ? EmplaceIndex(dwIndex) : EraseIndex(dwIndex);
- if(f1 < 0) {::InterlockedDecrement(&m_dwCount); ++(*(m_px + dwRealIndex));}
- if(!bSetValueFirst) INDEX_VAL(dwRealIndex) = pElement;
- ASSERT(Spaces() <= Size());
- return TRUE;
- }
- BOOL Remove(index_type dwIndex, TPTR* ppElement = nullptr)
- {
- return Set(dwIndex, E_EMPTY, ppElement);
- }
- BOOL AcquireLock(index_type& dwIndex)
- {
- return Put(E_LOCKED, dwIndex);
- }
- BOOL ReleaseLock(index_type dwIndex, TPTR pElement)
- {
- ASSERT(pElement == nullptr || IsValidElement(pElement));
- TPTR pElement2 = nullptr;
- Get(dwIndex, &pElement2);
- ASSERT(pElement2 == E_LOCKED);
- if(pElement2 != E_LOCKED)
- return FALSE;
- return Set(dwIndex, pElement);
- }
- public:
- void Reset(DWORD dwSize = 0)
- {
- if(IsValid())
- Destroy();
- if(dwSize > 0)
- Create(dwSize);
- }
-
- BOOL GetAllElementIndexes(index_type ids[], DWORD& dwCount, BOOL bCopy = TRUE)
- {
- if(ids == nullptr || dwCount == 0)
- {
- dwCount = Elements();
- return FALSE;
- }
- IndexSet* pIndexes = nullptr;
- IndexSet indexes;
- if(bCopy)
- pIndexes = &CopyIndexes(indexes);
- else
- pIndexes = &m_indexes;
- BOOL isOK = FALSE;
- DWORD dwSize = (DWORD)pIndexes->size();
- if(dwSize > 0 && dwSize <= dwCount)
- {
- IndexSetCI it = pIndexes->begin();
- IndexSetCI end = pIndexes->end();
- for(int i = 0; it != end; ++it, ++i)
- ids[i] = *it;
- isOK = TRUE;
- }
- dwCount = dwSize;
- return isOK;
- }
-
- unique_ptr<index_type[]> GetAllElementIndexes(DWORD& dwCount, BOOL bCopy = TRUE)
- {
- IndexSet* pIndexes = nullptr;
- IndexSet indexes;
- if(bCopy)
- pIndexes = &CopyIndexes(indexes);
- else
- pIndexes = &m_indexes;
- unique_ptr<index_type[]> ids;
- dwCount = (DWORD)pIndexes->size();
- if(dwCount > 0)
- {
- ids.reset(new index_type[dwCount]);
- IndexSetCI it = pIndexes->begin();
- IndexSetCI end = pIndexes->end();
- for(int i = 0; it != end; ++it, ++i)
- ids[i] = *it;
- }
- return ids;
- }
- static BOOL IsValidElement(TPTR pElement) {return pElement > E_MAX_STATUS;}
- DWORD Size () {return m_dwSize;}
- DWORD Elements () {return (DWORD)m_indexes.size();}
- DWORD Spaces () {return m_dwSize - m_dwCount;}
- BOOL HasSpace () {return m_dwCount < m_dwSize;}
- BOOL IsEmpty () {return m_dwCount == 0;}
- BOOL IsValid () {return m_pv != nullptr;}
- private:
- void Create(DWORD dwSize)
- {
- ASSERT(!IsValid() && dwSize > 0 && dwSize <= MAX_SIZE);
- m_dwCurSeq = 0;
- m_dwCount = 0;
- m_dwSize = dwSize;
- m_pv = (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
- m_px = (BYTE*)malloc(m_dwSize * sizeof(BYTE));
- ::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
- ::ZeroMemory(m_px, m_dwSize * sizeof(BYTE));
- }
- void Destroy()
- {
- ASSERT(IsValid());
- m_indexes.clear();
- free((void*)m_pv);
- free((void*)m_px);
- m_pv = nullptr;
- m_px = nullptr;
- m_dwSize = 0;
- m_dwCount = 0;
- m_dwCurSeq = 0;
- }
- IndexSet& CopyIndexes(IndexSet& indexes)
- {
- {
- CReadLock locallock(m_cs);
- indexes = m_indexes;
- }
- return indexes;
- }
- void EmplaceIndex(index_type dwIndex)
- {
- CWriteLock locallock(m_cs);
- m_indexes.emplace(dwIndex);
- }
- void EraseIndex(index_type dwIndex)
- {
- CWriteLock locallock(m_cs);
- m_indexes.erase(dwIndex);
- }
- public:
- CRingCache2 (DWORD dwSize = 0)
- : m_pv (nullptr)
- , m_px (nullptr)
- , m_dwSize (0)
- , m_dwCount (0)
- , m_dwCurSeq(0)
- {
- Reset(dwSize);
- }
- ~CRingCache2()
- {
- Reset(0);
- }
- private:
- CRingCache2(const CRingCache2&);
- CRingCache2 operator = (const CRingCache2&);
- private:
- DWORD m_dwSize;
- VTPTR* m_pv;
- char pack1[PACK_SIZE_OF(VTPTR*)];
- BYTE* m_px;
- char pack2[PACK_SIZE_OF(BYTE*)];
- volatile DWORD m_dwCurSeq;
- char pack3[PACK_SIZE_OF(DWORD)];
- volatile DWORD m_dwCount;
- char pack4[PACK_SIZE_OF(DWORD)];
- CSimpleRWLock m_cs;
- IndexSet m_indexes;
- };
- template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_EMPTY = (T*)0x00;
- template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_LOCKED = (T*)0x01;
- template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_MAX_STATUS = (T*)0x0F;
- template <class T, class index_type, bool adjust_index> DWORD const CRingCache2<T, index_type, adjust_index>::MAX_SIZE =
- #if !defined(_WIN64)
- 0x00FFFFFF
- #else
- 0xFFFFFFFF
- #endif
- ;
- // ------------------------------------------------------------------------------------------------------------- //
- template <class T> class CRingPool
- {
- private:
- typedef T* TPTR;
- typedef volatile T* VTPTR;
- static TPTR const E_EMPTY;
- static TPTR const E_LOCKED;
- static TPTR const E_RELEASED;
- static TPTR const E_OCCUPIED;
- static TPTR const E_MAX_STATUS;
- private:
- VTPTR& INDEX_VAL(DWORD dwIndex) {return *(m_pv + dwIndex);}
- public:
- BOOL TryPut(TPTR pElement)
- {
- ASSERT(pElement != nullptr);
- if(!IsValid()) return FALSE;
- BOOL isOK = FALSE;
- while(true)
- {
- BOOL bOccupy = FALSE;
- DWORD seqPut = m_seqPut;
- if(!HasPutSpace(seqPut))
- break;
- DWORD dwIndex = seqPut % m_dwSize;
- VTPTR& pValue = INDEX_VAL(dwIndex);
- if(pValue == E_RELEASED)
- {
- if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, E_OCCUPIED, E_RELEASED) == E_RELEASED)
- bOccupy = TRUE;
- else
- continue;
- }
- if(pValue == E_EMPTY || bOccupy)
- {
- if(::InterlockedCompareExchange(&m_seqPut, seqPut + 1, seqPut) == seqPut)
- {
- pValue = pElement;
- isOK = TRUE;
- break;
- }
- }
- else if(pValue == E_LOCKED)
- break;
- }
- return isOK;
- }
- BOOL TryGet(TPTR* ppElement)
- {
- ASSERT(ppElement != nullptr);
- if(!IsValid()) return FALSE;
- BOOL isOK = FALSE;
- while(true)
- {
- DWORD seqGet = m_seqGet;
- if(!HasGetSpace(seqGet))
- break;
- DWORD dwIndex = seqGet % m_dwSize;
- VTPTR& pValue = INDEX_VAL(dwIndex);
- if(pValue == E_LOCKED)
- break;
- else if(pValue != E_EMPTY && pValue != E_RELEASED && pValue != E_OCCUPIED)
- {
- if(::InterlockedCompareExchange(&m_seqGet, seqGet + 1, seqGet) == seqGet)
- {
- ASSERT(pValue > E_MAX_STATUS);
- *(ppElement) = (TPTR)pValue;
- pValue = E_EMPTY;
- isOK = TRUE;
- break;
- }
- }
- }
- return isOK;
- }
- BOOL TryLock(TPTR* ppElement, DWORD& dwIndex)
- {
- ASSERT(ppElement != nullptr);
- if(!IsValid()) return FALSE;
- BOOL isOK = FALSE;
- while(true)
- {
- DWORD seqGet = m_seqGet;
- if(!HasGetSpace(seqGet))
- break;
- dwIndex = seqGet % m_dwSize;
- VTPTR& pValue = INDEX_VAL(dwIndex);
- if(pValue == E_LOCKED)
- break;
- else if(pValue != E_EMPTY && pValue != E_RELEASED && pValue != E_OCCUPIED)
- {
- if(::InterlockedCompareExchange(&m_seqGet, seqGet + 1, seqGet) == seqGet)
- {
- ASSERT(pValue > E_MAX_STATUS);
- *(ppElement) = (TPTR)pValue;
- pValue = E_LOCKED;
- isOK = TRUE;
- break;
- }
- }
- }
- return isOK;
- }
- BOOL ReleaseLock(TPTR pElement, DWORD dwIndex)
- {
- ASSERT(dwIndex < m_dwSize);
- ASSERT(pElement == nullptr || pElement > E_MAX_STATUS);
- if(!IsValid()) return FALSE;
- VTPTR& pValue = INDEX_VAL(dwIndex);
- VERIFY(pValue == E_LOCKED);
- if(pElement != nullptr)
- {
- for(DWORD i = 0; ; i++)
- {
- if(TryPut(pElement))
- break;
- DWORD dwPutIndex = m_seqPut % m_dwSize;
- if(dwIndex == dwPutIndex)
- {
- pValue = pElement;
- ::InterlockedIncrement(&m_seqPut);
- return TRUE;
- }
- ::YieldThread(i);
- }
- }
- pValue = E_RELEASED;
- return TRUE;
- }
- public:
- void Reset(DWORD dwSize = 0)
- {
- if(IsValid())
- Destroy();
- if(dwSize > 0)
- Create(dwSize);
- }
- DWORD Size() {return m_dwSize;}
- DWORD Elements() {return m_seqPut - m_seqGet;}
- BOOL IsFull() {return Elements() == Size();}
- BOOL IsEmpty() {return Elements() == 0;}
- BOOL IsValid() {return m_pv != nullptr;}
- private:
- BOOL HasPutSpace(DWORD seqPut)
- {
- return ((int)(seqPut - m_seqGet) < (int)m_dwSize);
- }
- BOOL HasGetSpace(DWORD seqGet)
- {
- return ((int)(m_seqPut - seqGet) > 0);
- }
- void Create(DWORD dwSize)
- {
- ASSERT(!IsValid() && dwSize > 0);
- m_seqPut = 0;
- m_seqGet = 0;
- m_dwSize = dwSize;
- m_pv = (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
- ::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
- }
- void Destroy()
- {
- ASSERT(IsValid());
- free((void*)m_pv);
- m_pv = nullptr;
- m_dwSize = 0;
- m_seqPut = 0;
- m_seqGet = 0;
- }
- public:
- CRingPool(DWORD dwSize = 0)
- : m_pv(nullptr)
- , m_dwSize(0)
- , m_seqPut(0)
- , m_seqGet(0)
- {
- Reset(dwSize);
- }
- ~CRingPool()
- {
- Reset(0);
- }
- private:
- CRingPool(const CRingPool&);
- CRingPool operator = (const CRingPool&);
- private:
- DWORD m_dwSize;
- VTPTR* m_pv;
- char pack1[PACK_SIZE_OF(VTPTR*)];
- volatile DWORD m_seqPut;
- char pack2[PACK_SIZE_OF(DWORD)];
- volatile DWORD m_seqGet;
- char pack3[PACK_SIZE_OF(DWORD)];
- };
- template <class T> T* const CRingPool<T>::E_EMPTY = (T*)0x00;
- template <class T> T* const CRingPool<T>::E_LOCKED = (T*)0x01;
- template <class T> T* const CRingPool<T>::E_RELEASED = (T*)0x02;
- template <class T> T* const CRingPool<T>::E_OCCUPIED = (T*)0x03;
- template <class T> T* const CRingPool<T>::E_MAX_STATUS = (T*)0x0F;
- // ------------------------------------------------------------------------------------------------------------- //
- template <class T> class CCASQueue
- {
- private:
- struct Node;
- typedef Node* NPTR;
- typedef volatile Node* VNPTR;
- typedef volatile ULONG VLONG;
- struct Node
- {
- T* pValue;
- VNPTR pNext;
- Node(T* val, NPTR next = nullptr)
- : pValue(val), pNext(next)
- {
- }
- };
- public:
- void PushBack(T* pVal)
- {
- ASSERT(pVal != nullptr);
- VNPTR pTail = nullptr;
- NPTR pNode = new Node(pVal);
- while(true)
- {
- pTail = m_pTail;
- if(::InterlockedCompareExchangePointer((volatile PVOID*)&m_pTail, (PVOID)pNode, (PVOID)pTail) == pTail)
- {
- pTail->pNext = pNode;
- break;
- }
- }
- ::InterlockedIncrement(&m_lSize);
- }
- void UnsafePushBack(T* pVal)
- {
- ASSERT(pVal != nullptr);
- NPTR pNode = new Node(pVal);
- m_pTail->pNext = pNode;
- m_pTail = pNode;
-
- ::InterlockedIncrement(&m_lSize);
- }
- BOOL PopFront(T** ppVal)
- {
- ASSERT(ppVal != nullptr);
- if(IsEmpty())
- return FALSE;
- BOOL isOK = FALSE;
- NPTR pHead = nullptr;
- NPTR pNext = nullptr;
- T* pVal = nullptr;
- while(true)
- {
- while(::InterlockedCompareExchange(&m_lLock, 1, 0) != 0)
- ::YieldProcessor();
- pHead = (NPTR)m_pHead;
- pNext = (NPTR)pHead->pNext;
- if(pNext == nullptr)
- {
- m_lLock = 0;
- break;
- }
- *ppVal = pNext->pValue;
- m_pHead = pNext;
- m_lLock = 0;
- isOK = TRUE;
- ::InterlockedDecrement(&m_lSize);
- delete pHead;
- break;
- }
- return isOK;
- }
- BOOL UnsafePopFront(T** ppVal)
- {
- if(!UnsafePeekFront(ppVal))
- return FALSE;
- NPTR pHead = (NPTR)m_pHead;
- NPTR pNext = (NPTR)pHead->pNext;
- m_pHead = pNext;
- ::InterlockedDecrement(&m_lSize);
- delete pHead;
- return TRUE;
- }
- BOOL UnsafePeekFront(T** ppVal)
- {
- ASSERT(ppVal != nullptr);
- NPTR pNext = (NPTR)m_pHead->pNext;
- if(pNext == nullptr)
- return FALSE;
- *ppVal = pNext->pValue;
- return TRUE;
- }
- public:
- ULONG Size() {return m_lSize;}
- BOOL IsEmpty() {return m_lSize == 0;}
- public:
- CCASQueue() : m_lLock(0), m_lSize(0)
- {
- NPTR pHead = new Node(nullptr);
- m_pHead = m_pTail = pHead;
- }
- ~CCASQueue()
- {
- ASSERT(m_lLock == 0);
- ASSERT(m_lSize == 0);
- ASSERT(m_pHead != nullptr);
- ASSERT(m_pHead->pNext == nullptr);
- while(m_pHead != nullptr)
- {
- VNPTR pNode = m_pHead->pNext;
- delete m_pHead;
- m_pHead = pNode;
- }
- }
- private:
- VLONG m_lLock;
- VLONG m_lSize;
- VNPTR m_pHead;
- VNPTR m_pTail;
- };
- #if !defined (_WIN64)
- #pragma pack(pop)
- #endif
|