开源的socket服务端客户端,支持C# C++

RingBuffer.h 28KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Version : 2.3.17
  5. * Author : Bruce Liang
  6. * Website : http://www.jessma.org
  7. * Project : https://github.com/ldcsaa
  8. * Blog : http://www.cnblogs.com/ldcsaa
  9. * Wiki : http://www.oschina.net/p/hp-socket
  10. * QQ Group : 75375912
  11. *
  12. * Licensed under the Apache License, Version 2.0 (the "License");
  13. * you may not use this file except in compliance with the License.
  14. * You may obtain a copy of the License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the License is distributed on an "AS IS" BASIS,
  20. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. * See the License for the specific language governing permissions and
  22. * limitations under the License.
  23. */
  24. #pragma once
  25. #include "STLHelper.h"
  26. #include "RWLock.h"
  27. #include "CriticalSection.h"
  28. #define CACHE_LINE 64
  29. #define PACK_SIZE_OF(T) (CACHE_LINE - sizeof(T) % CACHE_LINE)
  30. #if !defined (_WIN64)
  31. #pragma pack(push, 4)
  32. #endif
  33. template <class T, class _PutGuard = CCriSec, class _GetGuard = CCriSec> class CRingBuffer
  34. {
  35. public:
  36. static const UINT DEFAULT_EXPECT = 4096;
  37. public:
  38. BOOL Put(T* pElement)
  39. {
  40. ASSERT(pElement != nullptr);
  41. {
  42. CLocalLock<_PutGuard> locallock(m_csPut);
  43. ULONGLONG seqPut = m_seqPut;
  44. WaitForPut(seqPut);
  45. if(!IsValid()) return FALSE;
  46. DoPut(pElement, seqPut);
  47. }
  48. return TRUE;
  49. }
  50. BOOL TryPut(T* pElement)
  51. {
  52. ASSERT(pElement != nullptr);
  53. if(!IsValid() || !HasPutSpace(m_seqPut))
  54. return FALSE;
  55. {
  56. CLocalLock<_PutGuard> locallock(m_csPut);
  57. ULONGLONG seqPut = m_seqPut;
  58. if(!IsValid() || !HasPutSpace(seqPut))
  59. return FALSE;
  60. DoPut(pElement, seqPut);
  61. }
  62. return TRUE;
  63. }
  64. BOOL PutBatch(T* pElements[], int& iCount)
  65. {
  66. ASSERT(pElements != nullptr && iCount > 0);
  67. {
  68. CLocalLock<_PutGuard> locallock(m_csPut);
  69. ULONGLONG seqPut = m_seqPut;
  70. for(int i = 0; i < iCount; ++i)
  71. {
  72. WaitForPut(seqPut);
  73. if(!IsValid())
  74. {
  75. iCount = i;
  76. return FALSE;
  77. }
  78. DoPut(*(pElements + i), seqPut);
  79. }
  80. }
  81. return TRUE;
  82. }
  83. BOOL TryPutBatch(T* pElements[], int& iCount)
  84. {
  85. ASSERT(pElements != nullptr && iCount > 0);
  86. if(!IsValid() || !HasPutSpace(m_seqPut))
  87. {
  88. iCount = 0;
  89. return FALSE;
  90. }
  91. {
  92. CLocalLock<_PutGuard> locallock(m_csPut);
  93. ULONGLONG seqPut = m_seqPut;
  94. for(int i = 0; i < iCount; ++i)
  95. {
  96. if(!IsValid() || !HasPutSpace(seqPut))
  97. {
  98. iCount = i;
  99. return FALSE;
  100. }
  101. DoPut(*(pElements + i), seqPut);
  102. }
  103. }
  104. return TRUE;
  105. }
  106. BOOL Get(T** pElement)
  107. {
  108. ASSERT(pElement != nullptr);
  109. {
  110. CLocalLock<_GetGuard> locallock(m_csGet);
  111. ULONGLONG seqGet = m_seqGet;
  112. WaitForGet(seqGet);
  113. if(!IsValid()) return FALSE;
  114. DoGet(pElement, seqGet);
  115. }
  116. return TRUE;
  117. }
  118. BOOL TryGet(T** pElement)
  119. {
  120. ASSERT(pElement != nullptr);
  121. if(!IsValid() || !HasGetSpace(m_seqGet))
  122. return FALSE;
  123. {
  124. CLocalLock<_GetGuard> locallock(m_csGet);
  125. ULONGLONG seqGet = m_seqGet;
  126. if(!IsValid() || !HasGetSpace(seqGet))
  127. return FALSE;
  128. DoGet(pElement, seqGet);
  129. }
  130. return TRUE;
  131. }
  132. BOOL GetBatch(T* pElements[], int& iCount)
  133. {
  134. ASSERT(pElements != nullptr && iCount > 0);
  135. {
  136. CLocalLock<_GetGuard> locallock(m_csGet);
  137. ULONGLONG seqGet = m_seqGet;
  138. for(int i = 0; i < iCount; ++i)
  139. {
  140. WaitForGet(seqGet);
  141. if(!IsValid())
  142. {
  143. iCount = i;
  144. return FALSE;
  145. }
  146. DoGet(pElements + i, seqGet);
  147. }
  148. }
  149. return TRUE;
  150. }
  151. BOOL TryGetBatch(T* pElements[], int& iCount)
  152. {
  153. ASSERT(pElements != nullptr && iCount > 0);
  154. if(!IsValid() || !HasGetSpace(m_seqGet))
  155. {
  156. iCount = 0;
  157. return FALSE;
  158. }
  159. {
  160. CLocalLock<_GetGuard> locallock(m_csGet);
  161. ULONGLONG seqGet = m_seqGet;
  162. for(int i = 0; i < iCount; ++i)
  163. {
  164. if(!IsValid() || !HasGetSpace(seqGet))
  165. {
  166. iCount = i;
  167. return FALSE;
  168. }
  169. DoGet(pElements + i, seqGet);
  170. }
  171. }
  172. return TRUE;
  173. }
  174. BOOL Peek(T** pElement)
  175. {
  176. ASSERT(pElement != nullptr);
  177. ULONGLONG seqGet = m_seqGet;
  178. if(!IsValid() || !HasGetSpace(seqGet))
  179. return FALSE;
  180. DoPeek(pElement, seqGet);
  181. return TRUE;
  182. }
  183. BOOL Create(DWORD dwExpect = DEFAULT_EXPECT)
  184. {
  185. ASSERT(!IsValid() && dwExpect > 0);
  186. if(IsValid()) return FALSE;
  187. m_seqPut = 0;
  188. m_seqGet = 0;
  189. m_dwReal = Revise(dwExpect);
  190. m_pv = (T**)malloc(m_dwReal * sizeof(T*));
  191. m_bValid = (m_pv != nullptr);
  192. return IsValid();
  193. }
  194. BOOL Destroy()
  195. {
  196. if(IsValid())
  197. {
  198. m_bValid = FALSE;
  199. CLocalLock<_PutGuard> locallock1(m_csPut);
  200. CLocalLock<_GetGuard> locallock2(m_csGet);
  201. free((void*)m_pv);
  202. m_pv = nullptr;
  203. m_dwReal = 0;
  204. m_seqPut = 0;
  205. m_seqGet = 0;
  206. return TRUE;
  207. }
  208. return FALSE;
  209. }
  210. private:
  211. void DoPut(T* pElement, ULONGLONG& seqPut)
  212. {
  213. DWORD index = seqPut & (m_dwReal - 1);
  214. *(m_pv + index) = pElement;
  215. ++seqPut;
  216. m_seqPut = seqPut;
  217. }
  218. void DoGet(T** pElement, ULONGLONG& seqGet)
  219. {
  220. DWORD index = seqGet & (m_dwReal - 1);
  221. *(pElement) = *(m_pv + index);
  222. ++seqGet;
  223. m_seqGet = seqGet;
  224. }
  225. void DoPeek(T** pElement, ULONGLONG& seqGet)
  226. {
  227. DWORD index = seqGet & (m_dwReal - 1);
  228. *(pElement) = *(m_pv + index);
  229. }
  230. BOOL HasPutSpace(ULONGLONG seqPut)
  231. {
  232. return (seqPut - m_seqGet < m_dwReal);
  233. }
  234. void WaitForPut(ULONGLONG seqPut)
  235. {
  236. for(DWORD w = 0; IsValid(); ++w)
  237. {
  238. if(HasPutSpace(seqPut))
  239. break;
  240. ::YieldThread(w);
  241. }
  242. }
  243. BOOL HasGetSpace(ULONGLONG seqGet)
  244. {
  245. return (m_seqPut - seqGet > 0);
  246. }
  247. void WaitForGet(ULONGLONG seqGet)
  248. {
  249. for(DWORD w = 0; IsValid(); ++w)
  250. {
  251. if(HasGetSpace(seqGet))
  252. break;
  253. ::YieldThread(w);
  254. }
  255. }
  256. DWORD Revise(DWORD dwExpect)
  257. {
  258. int index = 0;
  259. int shift = sizeof(DWORD) * 8 - 1;
  260. for(int i = shift; i >= 0; i--)
  261. {
  262. if(index == 0)
  263. {
  264. if(dwExpect & (1 << i))
  265. {
  266. index = i;
  267. if(index == shift)
  268. break;
  269. }
  270. }
  271. else
  272. {
  273. if(dwExpect & (1 << i))
  274. ++index;
  275. break;
  276. }
  277. }
  278. return 1 << index;
  279. }
  280. public:
  281. CRingBuffer(BOOL bCreate = FALSE, DWORD uiExpect = DEFAULT_EXPECT)
  282. : m_pv(nullptr)
  283. , m_bValid(FALSE)
  284. , m_dwReal(0)
  285. , m_seqPut(0)
  286. , m_seqGet(0)
  287. {
  288. ASSERT(uiExpect > 0);
  289. if(bCreate)
  290. {
  291. Create(uiExpect);
  292. ASSERT(IsValid());
  293. }
  294. }
  295. ~CRingBuffer()
  296. {
  297. Destroy();
  298. }
  299. BOOL IsValid() {return m_bValid;}
  300. private:
  301. CRingBuffer(const CRingBuffer&);
  302. CRingBuffer operator = (const CRingBuffer&);
  303. private:
  304. BOOL m_bValid;
  305. DWORD m_dwReal;
  306. T** m_pv;
  307. char pack1[PACK_SIZE_OF(T**)];
  308. volatile ULONGLONG m_seqPut;
  309. char pack4[PACK_SIZE_OF(ULONGLONG)];
  310. volatile ULONGLONG m_seqGet;
  311. char pack5[PACK_SIZE_OF(ULONGLONG)];
  312. _PutGuard m_csPut;
  313. char pack2[PACK_SIZE_OF(_PutGuard)];
  314. _GetGuard m_csGet;
  315. char pack3[PACK_SIZE_OF(_GetGuard)];
  316. };
  317. typedef CRingBuffer<void, CCriSec, CCriSec> CCSRingBuffer;
  318. typedef CRingBuffer<void, CInterCriSec, CInterCriSec> CICSRingBuffer;
  319. typedef CRingBuffer<void, CSpinGuard, CSpinGuard> CSGRingBuffer;
  320. typedef CRingBuffer<void, CFakeGuard, CFakeGuard> CFKRingBuffer;
  321. // ------------------------------------------------------------------------------------------------------------- //
  322. template <class T, class index_type = DWORD, bool adjust_index = false> class CRingCache
  323. {
  324. public:
  325. enum EnGetResult {GR_FAIL = -1, GR_INVALID = 0, GR_VALID = 1};
  326. typedef T* TPTR;
  327. typedef volatile T* VTPTR;
  328. typedef unordered_set<index_type> IndexSet;
  329. typedef typename IndexSet::const_iterator IndexSetCI;
  330. typedef typename IndexSet::iterator IndexSetI;
  331. static TPTR const E_EMPTY;
  332. static TPTR const E_LOCKED;
  333. static TPTR const E_MAX_STATUS;
  334. public:
  335. static index_type& INDEX_INC(index_type& dwIndex) {if(adjust_index) ++dwIndex; return dwIndex;}
  336. static index_type& INDEX_DEC(index_type& dwIndex) {if(adjust_index) --dwIndex; return dwIndex;}
  337. private:
  338. VTPTR& INDEX_VAL(index_type dwIndex) {return *(m_pv + dwIndex);}
  339. public:
  340. BOOL Put(TPTR pElement, index_type& dwIndex)
  341. {
  342. ASSERT(pElement != nullptr);
  343. BOOL isOK = FALSE;
  344. while(true)
  345. {
  346. if(!HasSpace())
  347. break;
  348. DWORD dwCurSeq = m_dwCurSeq;
  349. index_type dwCurIndex = dwCurSeq % m_dwSize;
  350. VTPTR& pValue = INDEX_VAL(dwCurIndex);
  351. if(pValue == E_EMPTY)
  352. {
  353. if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, pElement, E_EMPTY) == E_EMPTY)
  354. {
  355. ::InterlockedIncrement(&m_dwCount);
  356. ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
  357. dwIndex = INDEX_INC(dwCurIndex);
  358. isOK = TRUE;
  359. if(pElement != E_LOCKED)
  360. EmplaceIndex(dwIndex);
  361. break;
  362. }
  363. }
  364. ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
  365. }
  366. return isOK;
  367. }
  368. EnGetResult Get(index_type dwIndex, TPTR* ppElement)
  369. {
  370. ASSERT(dwIndex <= m_dwSize);
  371. ASSERT(ppElement != nullptr);
  372. if(INDEX_DEC(dwIndex) >= m_dwSize)
  373. {
  374. *ppElement = nullptr;
  375. return GR_FAIL;
  376. }
  377. *ppElement = (TPTR)INDEX_VAL(dwIndex);
  378. return IsValidElement(*ppElement) ? GR_VALID : GR_INVALID;
  379. }
  380. BOOL Set(index_type dwIndex, TPTR pElement, TPTR* ppOldElement = nullptr)
  381. {
  382. TPTR pElement2 = nullptr;
  383. if(Get(dwIndex, &pElement2) == GR_FAIL)
  384. return FALSE;
  385. if(ppOldElement != nullptr)
  386. *ppOldElement = pElement2;
  387. if(pElement == pElement2)
  388. return FALSE;
  389. int f1 = 0;
  390. int f2 = 0;
  391. if(pElement == E_EMPTY)
  392. {
  393. if(pElement2 == E_LOCKED)
  394. f1 = -1;
  395. else
  396. f1 = f2 = -1;
  397. }
  398. else if(pElement == E_LOCKED)
  399. {
  400. if(pElement2 == E_EMPTY)
  401. f1 = 1;
  402. else
  403. f2 = -1;
  404. }
  405. else
  406. {
  407. if(pElement2 == E_EMPTY)
  408. f1 = f2 = 1;
  409. else if(pElement2 == E_LOCKED)
  410. f2 = 1;
  411. }
  412. BOOL bSetValueFirst = (f1 + f2 >= 0);
  413. index_type dwOuterIndex = dwIndex;
  414. INDEX_DEC(dwIndex);
  415. if(bSetValueFirst) INDEX_VAL(dwIndex) = pElement;
  416. if(f1 > 0) ::InterlockedIncrement(&m_dwCount);
  417. if(f2 != 0) (f2 > 0) ? EmplaceIndex(dwOuterIndex) : EraseIndex(dwOuterIndex);
  418. if(f1 < 0) ::InterlockedDecrement(&m_dwCount);
  419. if(!bSetValueFirst) INDEX_VAL(dwIndex) = pElement;
  420. ASSERT(Spaces() <= Size());
  421. return TRUE;
  422. }
  423. BOOL Remove(index_type dwIndex, TPTR* ppElement = nullptr)
  424. {
  425. return Set(dwIndex, E_EMPTY, ppElement);
  426. }
  427. BOOL AcquireLock(index_type& dwIndex)
  428. {
  429. return Put(E_LOCKED, dwIndex);
  430. }
  431. BOOL ReleaseLock(index_type dwIndex, TPTR pElement)
  432. {
  433. ASSERT(pElement == nullptr || IsValidElement(pElement));
  434. TPTR pElement2 = nullptr;
  435. Get(dwIndex, &pElement2);
  436. ASSERT(pElement2 == E_LOCKED);
  437. if(pElement2 != E_LOCKED)
  438. return FALSE;
  439. return Set(dwIndex, pElement);
  440. }
  441. public:
  442. void Reset(DWORD dwSize = 0)
  443. {
  444. if(IsValid())
  445. Destroy();
  446. if(dwSize > 0)
  447. Create(dwSize);
  448. }
  449. BOOL GetAllElementIndexes(index_type ids[], DWORD& dwCount, BOOL bCopy = TRUE)
  450. {
  451. if(ids == nullptr || dwCount == 0)
  452. {
  453. dwCount = Elements();
  454. return FALSE;
  455. }
  456. IndexSet* pIndexes = nullptr;
  457. IndexSet indexes;
  458. if(bCopy)
  459. pIndexes = &CopyIndexes(indexes);
  460. else
  461. pIndexes = &m_indexes;
  462. BOOL isOK = FALSE;
  463. DWORD dwSize = (DWORD)pIndexes->size();
  464. if(dwSize > 0 && dwSize <= dwCount)
  465. {
  466. IndexSetCI it = pIndexes->begin();
  467. IndexSetCI end = pIndexes->end();
  468. for(int i = 0; it != end; ++it, ++i)
  469. ids[i] = *it;
  470. isOK = TRUE;
  471. }
  472. dwCount = dwSize;
  473. return isOK;
  474. }
  475. unique_ptr<index_type[]> GetAllElementIndexes(DWORD& dwCount, BOOL bCopy = TRUE)
  476. {
  477. IndexSet* pIndexes = nullptr;
  478. IndexSet indexes;
  479. if(bCopy)
  480. pIndexes = &CopyIndexes(indexes);
  481. else
  482. pIndexes = &m_indexes;
  483. unique_ptr<index_type[]> ids;
  484. dwCount = (DWORD)pIndexes->size();
  485. if(dwCount > 0)
  486. {
  487. ids.reset(new index_type[dwCount]);
  488. IndexSetCI it = pIndexes->begin();
  489. IndexSetCI end = pIndexes->end();
  490. for(int i = 0; it != end; ++it, ++i)
  491. ids[i] = *it;
  492. }
  493. return ids;
  494. }
  495. static BOOL IsValidElement(TPTR pElement) {return pElement > E_MAX_STATUS;}
  496. DWORD Size () {return m_dwSize;}
  497. DWORD Elements () {return (DWORD)m_indexes.size();}
  498. DWORD Spaces () {return m_dwSize - m_dwCount;}
  499. BOOL HasSpace () {return m_dwCount < m_dwSize;}
  500. BOOL IsEmpty () {return m_dwCount == 0;}
  501. BOOL IsValid () {return m_pv != nullptr;}
  502. private:
  503. void Create(DWORD dwSize)
  504. {
  505. ASSERT(!IsValid() && dwSize > 0);
  506. m_dwCurSeq = 0;
  507. m_dwCount = 0;
  508. m_dwSize = dwSize;
  509. m_pv = (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
  510. ::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
  511. }
  512. void Destroy()
  513. {
  514. ASSERT(IsValid());
  515. m_indexes.clear();
  516. free((void*)m_pv);
  517. m_pv = nullptr;
  518. m_dwSize = 0;
  519. m_dwCount = 0;
  520. m_dwCurSeq = 0;
  521. }
  522. IndexSet& CopyIndexes(IndexSet& indexes)
  523. {
  524. {
  525. CReadLock locallock(m_cs);
  526. indexes = m_indexes;
  527. }
  528. return indexes;
  529. }
  530. void EmplaceIndex(index_type dwIndex)
  531. {
  532. CWriteLock locallock(m_cs);
  533. m_indexes.emplace(dwIndex);
  534. }
  535. void EraseIndex(index_type dwIndex)
  536. {
  537. CWriteLock locallock(m_cs);
  538. m_indexes.erase(dwIndex);
  539. }
  540. public:
  541. CRingCache (DWORD dwSize = 0)
  542. : m_pv (nullptr)
  543. , m_dwSize (0)
  544. , m_dwCount (0)
  545. , m_dwCurSeq(0)
  546. {
  547. Reset(dwSize);
  548. }
  549. ~CRingCache()
  550. {
  551. Reset(0);
  552. }
  553. private:
  554. CRingCache(const CRingCache&);
  555. CRingCache operator = (const CRingCache&);
  556. private:
  557. DWORD m_dwSize;
  558. VTPTR* m_pv;
  559. char pack1[PACK_SIZE_OF(VTPTR*)];
  560. volatile DWORD m_dwCurSeq;
  561. char pack2[PACK_SIZE_OF(DWORD)];
  562. volatile DWORD m_dwCount;
  563. char pack3[PACK_SIZE_OF(DWORD)];
  564. CSimpleRWLock m_cs;
  565. IndexSet m_indexes;
  566. };
  567. template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_EMPTY = (T*)0x00;
  568. template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_LOCKED = (T*)0x01;
  569. template <class T, class index_type, bool adjust_index> T* const CRingCache<T, index_type, adjust_index>::E_MAX_STATUS = (T*)0x0F;
  570. // ------------------------------------------------------------------------------------------------------------- //
  571. template <class T, class index_type = DWORD, bool adjust_index = false> class CRingCache2
  572. {
  573. public:
  574. enum EnGetResult {GR_FAIL = -1, GR_INVALID = 0, GR_VALID = 1};
  575. typedef T* TPTR;
  576. typedef volatile T* VTPTR;
  577. typedef unordered_set<index_type> IndexSet;
  578. typedef typename IndexSet::const_iterator IndexSetCI;
  579. typedef typename IndexSet::iterator IndexSetI;
  580. static TPTR const E_EMPTY;
  581. static TPTR const E_LOCKED;
  582. static TPTR const E_MAX_STATUS;
  583. static DWORD const MAX_SIZE;
  584. public:
  585. static index_type& INDEX_INC(index_type& dwIndex) {if(adjust_index) ++dwIndex; return dwIndex;}
  586. static index_type& INDEX_DEC(index_type& dwIndex) {if(adjust_index) --dwIndex; return dwIndex;}
  587. index_type& INDEX_R2V(index_type& dwIndex) {dwIndex += *(m_px + dwIndex) * m_dwSize; return dwIndex;}
  588. BOOL INDEX_V2R(index_type& dwIndex)
  589. {
  590. index_type m = dwIndex % m_dwSize;
  591. BYTE x = *(m_px + m);
  592. if(dwIndex / m_dwSize != x)
  593. return FALSE;
  594. dwIndex = m;
  595. return TRUE;
  596. }
  597. private:
  598. VTPTR& INDEX_VAL(index_type dwIndex) {return *(m_pv + dwIndex);}
  599. public:
  600. BOOL Put(TPTR pElement, index_type& dwIndex)
  601. {
  602. ASSERT(pElement != nullptr);
  603. BOOL isOK = FALSE;
  604. while(true)
  605. {
  606. if(!HasSpace())
  607. break;
  608. DWORD dwCurSeq = m_dwCurSeq;
  609. index_type dwCurIndex = dwCurSeq % m_dwSize;
  610. VTPTR& pValue = INDEX_VAL(dwCurIndex);
  611. if(pValue == E_EMPTY)
  612. {
  613. if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, pElement, E_EMPTY) == E_EMPTY)
  614. {
  615. ::InterlockedIncrement(&m_dwCount);
  616. ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
  617. dwIndex = INDEX_INC(INDEX_R2V(dwCurIndex));
  618. isOK = TRUE;
  619. if(pElement != E_LOCKED)
  620. EmplaceIndex(dwIndex);
  621. break;
  622. }
  623. }
  624. ::InterlockedCompareExchange(&m_dwCurSeq, dwCurSeq + 1, dwCurSeq);
  625. }
  626. return isOK;
  627. }
  628. EnGetResult Get(index_type dwIndex, TPTR* ppElement, index_type* pdwRealIndex = nullptr)
  629. {
  630. ASSERT(ppElement != nullptr);
  631. if(!INDEX_V2R(INDEX_DEC(dwIndex)))
  632. {
  633. *ppElement = nullptr;
  634. return GR_FAIL;
  635. }
  636. *ppElement = (TPTR)INDEX_VAL(dwIndex);
  637. if(pdwRealIndex) *pdwRealIndex = dwIndex;
  638. return IsValidElement(*ppElement) ? GR_VALID : GR_INVALID;
  639. }
  640. BOOL Set(index_type dwIndex, TPTR pElement, TPTR* ppOldElement = nullptr, index_type* pdwRealIndex = nullptr)
  641. {
  642. TPTR pElement2 = nullptr;
  643. if(pdwRealIndex == nullptr)
  644. pdwRealIndex = (index_type*)_alloca(sizeof(index_type));
  645. if(Get(dwIndex, &pElement2, pdwRealIndex) == GR_FAIL)
  646. return FALSE;
  647. if(ppOldElement != nullptr)
  648. *ppOldElement = pElement2;
  649. if(pElement == pElement2)
  650. return FALSE;
  651. int f1 = 0;
  652. int f2 = 0;
  653. if(pElement == E_EMPTY)
  654. {
  655. if(pElement2 == E_LOCKED)
  656. f1 = -1;
  657. else
  658. f1 = f2 = -1;
  659. }
  660. else if(pElement == E_LOCKED)
  661. {
  662. if(pElement2 == E_EMPTY)
  663. f1 = 1;
  664. else
  665. f2 = -1;
  666. }
  667. else
  668. {
  669. if(pElement2 == E_EMPTY)
  670. f1 = f2 = 1;
  671. else if(pElement2 == E_LOCKED)
  672. f2 = 1;
  673. }
  674. BOOL bSetValueFirst = (f1 + f2 >= 0);
  675. index_type dwRealIndex = *pdwRealIndex;
  676. if(bSetValueFirst) INDEX_VAL(dwRealIndex) = pElement;
  677. if(f1 > 0) ::InterlockedIncrement(&m_dwCount);
  678. if(f2 != 0) (f2 > 0) ? EmplaceIndex(dwIndex) : EraseIndex(dwIndex);
  679. if(f1 < 0) {::InterlockedDecrement(&m_dwCount); ++(*(m_px + dwRealIndex));}
  680. if(!bSetValueFirst) INDEX_VAL(dwRealIndex) = pElement;
  681. ASSERT(Spaces() <= Size());
  682. return TRUE;
  683. }
  684. BOOL Remove(index_type dwIndex, TPTR* ppElement = nullptr)
  685. {
  686. return Set(dwIndex, E_EMPTY, ppElement);
  687. }
  688. BOOL AcquireLock(index_type& dwIndex)
  689. {
  690. return Put(E_LOCKED, dwIndex);
  691. }
  692. BOOL ReleaseLock(index_type dwIndex, TPTR pElement)
  693. {
  694. ASSERT(pElement == nullptr || IsValidElement(pElement));
  695. TPTR pElement2 = nullptr;
  696. Get(dwIndex, &pElement2);
  697. ASSERT(pElement2 == E_LOCKED);
  698. if(pElement2 != E_LOCKED)
  699. return FALSE;
  700. return Set(dwIndex, pElement);
  701. }
  702. public:
  703. void Reset(DWORD dwSize = 0)
  704. {
  705. if(IsValid())
  706. Destroy();
  707. if(dwSize > 0)
  708. Create(dwSize);
  709. }
  710. BOOL GetAllElementIndexes(index_type ids[], DWORD& dwCount, BOOL bCopy = TRUE)
  711. {
  712. if(ids == nullptr || dwCount == 0)
  713. {
  714. dwCount = Elements();
  715. return FALSE;
  716. }
  717. IndexSet* pIndexes = nullptr;
  718. IndexSet indexes;
  719. if(bCopy)
  720. pIndexes = &CopyIndexes(indexes);
  721. else
  722. pIndexes = &m_indexes;
  723. BOOL isOK = FALSE;
  724. DWORD dwSize = (DWORD)pIndexes->size();
  725. if(dwSize > 0 && dwSize <= dwCount)
  726. {
  727. IndexSetCI it = pIndexes->begin();
  728. IndexSetCI end = pIndexes->end();
  729. for(int i = 0; it != end; ++it, ++i)
  730. ids[i] = *it;
  731. isOK = TRUE;
  732. }
  733. dwCount = dwSize;
  734. return isOK;
  735. }
  736. unique_ptr<index_type[]> GetAllElementIndexes(DWORD& dwCount, BOOL bCopy = TRUE)
  737. {
  738. IndexSet* pIndexes = nullptr;
  739. IndexSet indexes;
  740. if(bCopy)
  741. pIndexes = &CopyIndexes(indexes);
  742. else
  743. pIndexes = &m_indexes;
  744. unique_ptr<index_type[]> ids;
  745. dwCount = (DWORD)pIndexes->size();
  746. if(dwCount > 0)
  747. {
  748. ids.reset(new index_type[dwCount]);
  749. IndexSetCI it = pIndexes->begin();
  750. IndexSetCI end = pIndexes->end();
  751. for(int i = 0; it != end; ++it, ++i)
  752. ids[i] = *it;
  753. }
  754. return ids;
  755. }
  756. static BOOL IsValidElement(TPTR pElement) {return pElement > E_MAX_STATUS;}
  757. DWORD Size () {return m_dwSize;}
  758. DWORD Elements () {return (DWORD)m_indexes.size();}
  759. DWORD Spaces () {return m_dwSize - m_dwCount;}
  760. BOOL HasSpace () {return m_dwCount < m_dwSize;}
  761. BOOL IsEmpty () {return m_dwCount == 0;}
  762. BOOL IsValid () {return m_pv != nullptr;}
  763. private:
  764. void Create(DWORD dwSize)
  765. {
  766. ASSERT(!IsValid() && dwSize > 0 && dwSize <= MAX_SIZE);
  767. m_dwCurSeq = 0;
  768. m_dwCount = 0;
  769. m_dwSize = dwSize;
  770. m_pv = (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
  771. m_px = (BYTE*)malloc(m_dwSize * sizeof(BYTE));
  772. ::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
  773. ::ZeroMemory(m_px, m_dwSize * sizeof(BYTE));
  774. }
  775. void Destroy()
  776. {
  777. ASSERT(IsValid());
  778. m_indexes.clear();
  779. free((void*)m_pv);
  780. free((void*)m_px);
  781. m_pv = nullptr;
  782. m_px = nullptr;
  783. m_dwSize = 0;
  784. m_dwCount = 0;
  785. m_dwCurSeq = 0;
  786. }
  787. IndexSet& CopyIndexes(IndexSet& indexes)
  788. {
  789. {
  790. CReadLock locallock(m_cs);
  791. indexes = m_indexes;
  792. }
  793. return indexes;
  794. }
  795. void EmplaceIndex(index_type dwIndex)
  796. {
  797. CWriteLock locallock(m_cs);
  798. m_indexes.emplace(dwIndex);
  799. }
  800. void EraseIndex(index_type dwIndex)
  801. {
  802. CWriteLock locallock(m_cs);
  803. m_indexes.erase(dwIndex);
  804. }
  805. public:
  806. CRingCache2 (DWORD dwSize = 0)
  807. : m_pv (nullptr)
  808. , m_px (nullptr)
  809. , m_dwSize (0)
  810. , m_dwCount (0)
  811. , m_dwCurSeq(0)
  812. {
  813. Reset(dwSize);
  814. }
  815. ~CRingCache2()
  816. {
  817. Reset(0);
  818. }
  819. private:
  820. CRingCache2(const CRingCache2&);
  821. CRingCache2 operator = (const CRingCache2&);
  822. private:
  823. DWORD m_dwSize;
  824. VTPTR* m_pv;
  825. char pack1[PACK_SIZE_OF(VTPTR*)];
  826. BYTE* m_px;
  827. char pack2[PACK_SIZE_OF(BYTE*)];
  828. volatile DWORD m_dwCurSeq;
  829. char pack3[PACK_SIZE_OF(DWORD)];
  830. volatile DWORD m_dwCount;
  831. char pack4[PACK_SIZE_OF(DWORD)];
  832. CSimpleRWLock m_cs;
  833. IndexSet m_indexes;
  834. };
  835. template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_EMPTY = (T*)0x00;
  836. template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_LOCKED = (T*)0x01;
  837. template <class T, class index_type, bool adjust_index> T* const CRingCache2<T, index_type, adjust_index>::E_MAX_STATUS = (T*)0x0F;
  838. template <class T, class index_type, bool adjust_index> DWORD const CRingCache2<T, index_type, adjust_index>::MAX_SIZE =
  839. #if !defined(_WIN64)
  840. 0x00FFFFFF
  841. #else
  842. 0xFFFFFFFF
  843. #endif
  844. ;
  845. // ------------------------------------------------------------------------------------------------------------- //
  846. template <class T> class CRingPool
  847. {
  848. private:
  849. typedef T* TPTR;
  850. typedef volatile T* VTPTR;
  851. static TPTR const E_EMPTY;
  852. static TPTR const E_LOCKED;
  853. static TPTR const E_RELEASED;
  854. static TPTR const E_OCCUPIED;
  855. static TPTR const E_MAX_STATUS;
  856. private:
  857. VTPTR& INDEX_VAL(DWORD dwIndex) {return *(m_pv + dwIndex);}
  858. public:
  859. BOOL TryPut(TPTR pElement)
  860. {
  861. ASSERT(pElement != nullptr);
  862. BOOL isOK = FALSE;
  863. while(true)
  864. {
  865. BOOL bOccupy = FALSE;
  866. DWORD seqPut = m_seqPut;
  867. if(!HasPutSpace(seqPut))
  868. break;
  869. DWORD dwIndex = seqPut % m_dwSize;
  870. VTPTR& pValue = INDEX_VAL(dwIndex);
  871. if(pValue == E_RELEASED)
  872. {
  873. if(::InterlockedCompareExchangePointer((volatile PVOID*)&pValue, E_OCCUPIED, E_RELEASED) == E_RELEASED)
  874. bOccupy = TRUE;
  875. else
  876. continue;
  877. }
  878. if(pValue == E_EMPTY || bOccupy)
  879. {
  880. if(::InterlockedCompareExchange(&m_seqPut, seqPut + 1, seqPut) == seqPut)
  881. {
  882. pValue = pElement;
  883. isOK = TRUE;
  884. break;
  885. }
  886. }
  887. else if(pValue == E_LOCKED)
  888. break;
  889. }
  890. return isOK;
  891. }
  892. BOOL TryGet(TPTR* ppElement)
  893. {
  894. ASSERT(ppElement != nullptr);
  895. BOOL isOK = FALSE;
  896. while(true)
  897. {
  898. DWORD seqGet = m_seqGet;
  899. if(!HasGetSpace(seqGet))
  900. break;
  901. DWORD dwIndex = seqGet % m_dwSize;
  902. VTPTR& pValue = INDEX_VAL(dwIndex);
  903. if(pValue == E_LOCKED)
  904. break;
  905. else if(pValue != E_EMPTY && pValue != E_RELEASED && pValue != E_OCCUPIED)
  906. {
  907. if(::InterlockedCompareExchange(&m_seqGet, seqGet + 1, seqGet) == seqGet)
  908. {
  909. ASSERT(pValue > E_MAX_STATUS);
  910. *(ppElement) = (TPTR)pValue;
  911. pValue = E_EMPTY;
  912. isOK = TRUE;
  913. break;
  914. }
  915. }
  916. }
  917. return isOK;
  918. }
  919. BOOL TryLock(TPTR* ppElement, DWORD& dwIndex)
  920. {
  921. ASSERT(ppElement != nullptr);
  922. BOOL isOK = FALSE;
  923. while(true)
  924. {
  925. DWORD seqGet = m_seqGet;
  926. if(!HasGetSpace(seqGet))
  927. break;
  928. dwIndex = seqGet % m_dwSize;
  929. VTPTR& pValue = INDEX_VAL(dwIndex);
  930. if(pValue == E_LOCKED)
  931. break;
  932. else if(pValue != E_EMPTY && pValue != E_RELEASED && pValue != E_OCCUPIED)
  933. {
  934. if(::InterlockedCompareExchange(&m_seqGet, seqGet + 1, seqGet) == seqGet)
  935. {
  936. ASSERT(pValue > E_MAX_STATUS);
  937. *(ppElement) = (TPTR)pValue;
  938. pValue = E_LOCKED;
  939. isOK = TRUE;
  940. break;
  941. }
  942. }
  943. }
  944. return isOK;
  945. }
  946. void ReleaseLock(TPTR pElement, DWORD dwIndex)
  947. {
  948. ASSERT(dwIndex < m_dwSize);
  949. ASSERT(pElement == nullptr || pElement > E_MAX_STATUS);
  950. VTPTR& pValue = INDEX_VAL(dwIndex);
  951. VERIFY(pValue == E_LOCKED);
  952. if(pElement != nullptr)
  953. {
  954. for(DWORD i = 0; ; i++)
  955. {
  956. if(TryPut(pElement))
  957. break;
  958. DWORD dwPutIndex = m_seqPut % m_dwSize;
  959. if(dwIndex == dwPutIndex)
  960. {
  961. pValue = pElement;
  962. ::InterlockedIncrement(&m_seqPut);
  963. return;
  964. }
  965. ::YieldThread(i);
  966. }
  967. }
  968. pValue = E_RELEASED;
  969. }
  970. public:
  971. void Reset(DWORD dwSize = 0)
  972. {
  973. if(IsValid())
  974. Destroy();
  975. if(dwSize > 0)
  976. Create(dwSize);
  977. }
  978. DWORD Size() {return m_dwSize;}
  979. DWORD Elements() {return m_seqPut - m_seqGet;}
  980. BOOL IsFull() {return Elements() == Size();}
  981. BOOL IsEmpty() {return Elements() == 0;}
  982. BOOL IsValid() {return m_pv != nullptr;}
  983. private:
  984. BOOL HasPutSpace(DWORD seqPut)
  985. {
  986. return (seqPut - m_seqGet < m_dwSize);
  987. }
  988. BOOL HasGetSpace(DWORD seqGet)
  989. {
  990. return (m_seqPut - seqGet > 0);
  991. }
  992. void Create(DWORD dwSize)
  993. {
  994. ASSERT(!IsValid() && dwSize > 0);
  995. m_seqPut = 0;
  996. m_seqGet = 0;
  997. m_dwSize = dwSize;
  998. m_pv = (VTPTR*)malloc(m_dwSize * sizeof(TPTR));
  999. ::ZeroMemory(m_pv, m_dwSize * sizeof(TPTR));
  1000. }
  1001. void Destroy()
  1002. {
  1003. ASSERT(IsValid());
  1004. free((void*)m_pv);
  1005. m_pv = nullptr;
  1006. m_dwSize = 0;
  1007. m_seqPut = 0;
  1008. m_seqGet = 0;
  1009. }
  1010. public:
  1011. CRingPool(DWORD dwSize = 0)
  1012. : m_pv(nullptr)
  1013. , m_dwSize(0)
  1014. , m_seqPut(0)
  1015. , m_seqGet(0)
  1016. {
  1017. Reset(dwSize);
  1018. }
  1019. ~CRingPool()
  1020. {
  1021. Reset(0);
  1022. }
  1023. private:
  1024. CRingPool(const CRingPool&);
  1025. CRingPool operator = (const CRingPool&);
  1026. private:
  1027. DWORD m_dwSize;
  1028. VTPTR* m_pv;
  1029. char pack1[PACK_SIZE_OF(VTPTR*)];
  1030. volatile DWORD m_seqPut;
  1031. char pack2[PACK_SIZE_OF(DWORD)];
  1032. volatile DWORD m_seqGet;
  1033. char pack3[PACK_SIZE_OF(DWORD)];
  1034. };
  1035. template <class T> T* const CRingPool<T>::E_EMPTY = (T*)0x00;
  1036. template <class T> T* const CRingPool<T>::E_LOCKED = (T*)0x01;
  1037. template <class T> T* const CRingPool<T>::E_RELEASED = (T*)0x02;
  1038. template <class T> T* const CRingPool<T>::E_OCCUPIED = (T*)0x03;
  1039. template <class T> T* const CRingPool<T>::E_MAX_STATUS = (T*)0x0F;
  1040. // ------------------------------------------------------------------------------------------------------------- //
  1041. template <class T> class CCASQueue
  1042. {
  1043. private:
  1044. struct Node;
  1045. typedef Node* NPTR;
  1046. typedef volatile Node* VNPTR;
  1047. typedef volatile ULONG VLONG;
  1048. struct Node
  1049. {
  1050. T* pValue;
  1051. VNPTR pNext;
  1052. Node(T* val, NPTR next = nullptr)
  1053. : pValue(val), pNext(next)
  1054. {
  1055. }
  1056. };
  1057. public:
  1058. void PushBack(T* pVal)
  1059. {
  1060. ASSERT(pVal != nullptr);
  1061. VNPTR pTail = nullptr;
  1062. NPTR pNode = new Node(pVal);
  1063. while(true)
  1064. {
  1065. pTail = m_pTail;
  1066. if(::InterlockedCompareExchangePointer((volatile PVOID*)&m_pTail, (PVOID)pNode, (PVOID)pTail) == pTail)
  1067. {
  1068. pTail->pNext = pNode;
  1069. break;
  1070. }
  1071. }
  1072. ::InterlockedIncrement(&m_lSize);
  1073. }
  1074. void UnsafePushBack(T* pVal)
  1075. {
  1076. ASSERT(pVal != nullptr);
  1077. NPTR pNode = new Node(pVal);
  1078. m_pTail->pNext = pNode;
  1079. m_pTail = pNode;
  1080. ::InterlockedIncrement(&m_lSize);
  1081. }
  1082. BOOL PopFront(T** ppVal)
  1083. {
  1084. ASSERT(ppVal != nullptr);
  1085. if(IsEmpty())
  1086. return FALSE;
  1087. BOOL isOK = FALSE;
  1088. NPTR pHead = nullptr;
  1089. NPTR pNext = nullptr;
  1090. T* pVal = nullptr;
  1091. while(true)
  1092. {
  1093. while(::InterlockedCompareExchange(&m_lLock, 1, 0) != 0)
  1094. ::YieldProcessor();
  1095. pHead = (NPTR)m_pHead;
  1096. pNext = (NPTR)pHead->pNext;
  1097. if(pNext == nullptr)
  1098. {
  1099. m_lLock = 0;
  1100. break;
  1101. }
  1102. *ppVal = pNext->pValue;
  1103. m_pHead = pNext;
  1104. m_lLock = 0;
  1105. isOK = TRUE;
  1106. ::InterlockedDecrement(&m_lSize);
  1107. delete pHead;
  1108. break;
  1109. }
  1110. return isOK;
  1111. }
  1112. BOOL UnsafePopFront(T** ppVal)
  1113. {
  1114. if(!UnsafePeekFront(ppVal))
  1115. return FALSE;
  1116. NPTR pHead = (NPTR)m_pHead;
  1117. NPTR pNext = (NPTR)pHead->pNext;
  1118. m_pHead = pNext;
  1119. ::InterlockedDecrement(&m_lSize);
  1120. delete pHead;
  1121. return TRUE;
  1122. }
  1123. BOOL UnsafePeekFront(T** ppVal)
  1124. {
  1125. ASSERT(ppVal != nullptr);
  1126. NPTR pNext = (NPTR)m_pHead->pNext;
  1127. if(pNext == nullptr)
  1128. return FALSE;
  1129. *ppVal = pNext->pValue;
  1130. return TRUE;
  1131. }
  1132. public:
  1133. ULONG Size() {return m_lSize;}
  1134. BOOL IsEmpty() {return m_lSize == 0;}
  1135. public:
  1136. CCASQueue() : m_lLock(0), m_lSize(0)
  1137. {
  1138. NPTR pHead = new Node(nullptr);
  1139. m_pHead = m_pTail = pHead;
  1140. }
  1141. ~CCASQueue()
  1142. {
  1143. ASSERT(m_lLock == 0);
  1144. ASSERT(m_lSize == 0);
  1145. ASSERT(m_pHead != nullptr);
  1146. ASSERT(m_pHead->pNext == nullptr);
  1147. while(m_pHead != nullptr)
  1148. {
  1149. VNPTR pNode = m_pHead->pNext;
  1150. delete m_pHead;
  1151. m_pHead = pNode;
  1152. }
  1153. }
  1154. private:
  1155. VLONG m_lLock;
  1156. VLONG m_lSize;
  1157. VNPTR m_pHead;
  1158. VNPTR m_pTail;
  1159. };
  1160. #if !defined (_WIN64)
  1161. #pragma pack(pop)
  1162. #endif