三种数据队列的实现
2014-06-25 10:46 钱吉 阅读(1323) 评论(0) 编辑 收藏 举报
1 /** 2 * 文件名称:dataqueue.h 3 * 摘 要:本文件实现了三种数据队列:简单队列,单队列类和双数据队列类。 4 1) 简单队列:使用List库,动态分配内存,使用临界区保证互斥 5 2)单队列:采用链表实现,一次性分配内存。减少频繁内存申请开销,同样采用临界区保存互斥。 6 3)双队列:包含两个单队列,采用ping-pong双缓冲策略,使得在多线程应用中,能保证最小的数据交换开销 7 * 当前版本:1.0 8 * 作 者:darkhorse 9 * 完成日期:2014-6-24 10 **/ 11 12 #ifndef __IMPLIMENT_DATA_QUEUE_H__ 13 #define __IMPLIMENT_DATA_QUEUE_H__ 14 15 #include <Windows.h> 16 #include <iostream> 17 #include <cstdio> 18 #include <cstdlib> 19 #include <assert.h> 20 #include <list> 21 namespace hw { 22 23 /*!< 队列满时再次分配数据的元素大小*/ 24 #define ONCE_MALLOC_SIZE 10 25 26 typedef enum Result { 27 NONE, 28 MEM_ALLOC_FAILED, 29 MEM_NOT_ENOUGH, 30 DATA_NOT_EXISTED, 31 32 }; 33 34 35 /******************************************************************/ 36 template<typename T> 37 class CSimpleQueue 38 { 39 public: 40 CSimpleQueue() 41 { 42 InitializeCriticalSection(&m_crit); 43 } 44 ~CSimpleQueue() 45 { 46 DeleteCriticalSection(&m_crit); 47 } 48 49 void pushData(const T &data) 50 { 51 EnterCriticalSection(&m_crit); 52 m_dataList.push_back(data); 53 LeaveCriticalSection(&m_crit); 54 } 55 56 BOOL popData(T &data) 57 { 58 EnterCriticalSection(&m_crit); 59 if (m_dataList.size() > 0) 60 { 61 data = m_dataList.front(); 62 m_dataList.pop_front(); 63 LeaveCriticalSection(&m_crit); 64 65 return TRUE; 66 } 67 else 68 { 69 LeaveCriticalSection(&m_crit); 70 return FALSE; 71 } 72 } 73 74 private: 75 std::list<T> m_dataList; 76 CRITICAL_SECTION m_crit; 77 }; 78 79 80 /*!< 链表元素*/ 81 template<typename T> 82 struct DataElement 83 { 84 T *m_pData; 85 DataElement *m_pNext; 86 87 DataElement() 88 { 89 reset(); 90 } 91 92 void reset() 93 { 94 m_pData = NULL; 95 m_pNext = NULL; 96 } 97 }; 98 99 /*********************** 单队列类*******************************/ 100 template <typename T> 101 class CSingleQueue 102 { 103 public: 104 CSingleQueue(unsigned int nSize = ONCE_MALLOC_SIZE); 105 ~CSingleQueue(); 106 107 void reset(); 108 BOOL pushData(const T &data); 109 BOOL popData(const T* &pData); 110 void removeHead(); /*!< 删除一条数据*/ 111 unsigned int getLen(); 112 BOOL isEmpty(); 113 114 private: 115 BOOL reAlloc(); 116 DataElement<T> *m_pHeadPos; /*!< 队列数据头*/ 117 DataElement<T> *m_pTailPos; /*!< 队列数据尾*/ 118 DataElement<T> *m_pFreePos; /*!< 空闲数据起始位置*/ 119 120 unsigned int m_nMaxSize; /*!< 队列包含的最大数据大小*/ 121 unsigned int m_nCurSize; /*!< 队列当前包含的数据元素大小*/ 122 T *m_pDataMem; /*!< 指向分配的数据*/ 123 }; 124 125 /*!< 类实现*/ 126 template<typename T> 127 CSingleQueue<T>::CSingleQueue(unsigned int nSize) 128 { 129 m_pDataMem = new T[nSize]; 130 if(NULL == m_pDataMem) 131 { 132 assert(FALSE); 133 } 134 m_nMaxSize = nSize; 135 m_nCurSize = 0; 136 m_pHeadPos = NULL; 137 m_pFreePos = NULL; 138 m_pTailPos = NULL; 139 } 140 141 template<typename T> 142 CSingleQueue<T>::~CSingleQueue() 143 { 144 reset(); 145 while(m_pFreePos != NULL) 146 { 147 DataElement<T> *pTemp = m_pFreePos; 148 m_pFreePos = m_pFreePos->m_pNext; 149 delete pTemp; 150 pTemp = NULL; 151 } 152 m_nCurSize = 0; 153 154 if(m_pDataMem != NULL) 155 { 156 delete []m_pDataMem; 157 m_pDataMem = NULL; 158 } 159 m_nMaxSize = 0; 160 } 161 162 /*!< 重置队列*/ 163 template<typename T> 164 void CSingleQueue<T>::reset() 165 { 166 while (m_pHeadPos != NULL) 167 { 168 DataElement<T> *pTemp = m_pHeadPos; 169 m_pHeadPos = m_pHeadPos->m_pNext; 170 pTemp->reset(); 171 pTemp->m_pNext = m_pFreePos; 172 m_pFreePos = pTemp; 173 } 174 m_nCurSize = 0; 175 m_pTailPos = NULL; 176 } 177 178 template<typename T> 179 BOOL CSingleQueue<T>::reAlloc() 180 { 181 for (unsigned int i=0; i<ONCE_MALLOC_SIZE; i++) 182 { 183 DataElement<T> *pTemp = new DataElement<T>; 184 if(NULL == pTemp) 185 { 186 assert(FALSE); 187 return FALSE; 188 } 189 pTemp->reset(); 190 pTemp->m_pNext = m_pFreePos; 191 m_pFreePos = pTemp; 192 } 193 return TRUE; 194 } 195 196 template<typename T> 197 BOOL CSingleQueue<T>::pushData(const T &data) 198 { 199 if(m_nCurSize >= m_nMaxSize) 200 { 201 return FALSE; 202 } 203 204 DataElement<T> *pTemp = NULL; 205 if(m_pFreePos != NULL) 206 { 207 pTemp = m_pFreePos;/*!< 找到第一个空闲结点*/ 208 m_pFreePos = m_pFreePos->m_pNext; 209 } 210 else 211 { 212 /*!< 如果没有空闲结点,再次分配*/ 213 if (reAlloc()) 214 { 215 if(m_pFreePos != NULL) 216 { 217 pTemp = m_pFreePos;/*!< 找到第一个空闲结点*/ 218 m_pFreePos = m_pFreePos->m_pNext; 219 } 220 } 221 } 222 if(pTemp != NULL) 223 { 224 m_pDataMem[m_nCurSize] = data;/*!< 先将数据拷贝到队列内存*/ 225 pTemp->reset(); 226 pTemp->m_pData = &m_pDataMem[m_nCurSize];/*!< 给数据成员赋值*/ 227 228 if(NULL == m_pHeadPos) 229 { 230 m_pHeadPos = pTemp; 231 } 232 else 233 { 234 m_pTailPos->m_pNext = pTemp; 235 } 236 m_pTailPos = pTemp; 237 238 m_nCurSize++; 239 return TRUE; 240 } 241 return FALSE; 242 } 243 244 template<typename T> 245 BOOL CSingleQueue<T>::popData(const T* &pData) 246 { 247 DataElement<T> *pTemp = m_pHeadPos; 248 if(pTemp != NULL) 249 { 250 pData = pTemp->m_pData; 251 return TRUE; 252 } 253 return FALSE; 254 } 255 256 template<typename T> 257 void CSingleQueue<T>::removeHead() 258 { 259 if (m_pHeadPos != NULL) 260 { 261 DataElement<T> *pTemp = m_pHeadPos; 262 m_pHeadPos = m_pHeadPos->m_pNext; 263 pTemp->reset(); 264 pTemp->m_pNext = m_pFreePos; 265 m_pFreePos = pTemp; 266 m_nCurSize--; 267 } 268 } 269 270 template<typename T> 271 unsigned int CSingleQueue<T>::getLen() 272 { 273 return m_nCurSize; 274 } 275 276 template<typename T> 277 BOOL CSingleQueue<T>::isEmpty() 278 { 279 return (m_pHeadPos == 0) ? TRUE : FALSE; 280 } 281 282 283 /****************************双队列类***************************/ 284 template<typename T> 285 class CDoubleQueue 286 { 287 public: 288 CDoubleQueue(); 289 ~CDoubleQueue(); 290 291 BOOL init(unsigned int nSize); 292 void release(); 293 294 BOOL pushData(const T &data); 295 BOOL popData(const T* &pData); 296 void removeHead(); 297 private: 298 CSingleQueue<T> *m_pPushList; 299 CSingleQueue<T> *m_pPopList; 300 CRITICAL_SECTION m_crit; 301 }; 302 303 /*!< 类的实现*/ 304 template<typename T> 305 CDoubleQueue<T>::CDoubleQueue() 306 { 307 m_pPushList = NULL; 308 m_pPopList = NULL; 309 InitializeCriticalSection(&m_crit); 310 } 311 312 template<typename T> 313 CDoubleQueue<T>::~CDoubleQueue() 314 { 315 DeleteCriticalSection(&m_crit); 316 } 317 318 template<typename T> 319 void CDoubleQueue<T>::release() 320 { 321 if(m_pPushList != NULL) 322 { 323 delete m_pPushList; 324 m_pPushList = NULL; 325 } 326 327 if(m_pPopList != NULL) 328 { 329 delete m_pPopList; 330 m_pPopList = NULL; 331 } 332 } 333 334 template<typename T> 335 BOOL CDoubleQueue<T>::init(unsigned int nSize) 336 { 337 if(nSize == 0) 338 { 339 return FALSE; 340 } 341 342 release(); 343 m_pPushList = new CSingleQueue<T>(nSize); 344 if(NULL == m_pPushList) 345 { 346 return FALSE; 347 } 348 349 m_pPopList = new CSingleQueue<T>(nSize); 350 if(NULL == m_pPopList) 351 { 352 return FALSE; 353 } 354 355 return TRUE; 356 } 357 358 template <class T> 359 BOOL CDoubleQueue<T>::pushData(const T &data) 360 { 361 BOOL bSuccess = FALSE; 362 EnterCriticalSection(&m_crit); 363 bSuccess = m_pPushList->pushData(data); 364 LeaveCriticalSection(&m_crit); 365 return bSuccess; 366 } 367 368 template <class T> 369 BOOL CDoubleQueue<T>::popData(const T* &pData) 370 { 371 BOOL bCouldRead = TRUE; 372 if(m_pPopList->isEmpty()) 373 { 374 EnterCriticalSection(&m_crit); 375 if(m_pPushList->isEmpty()) 376 { 377 LeaveCriticalSection(&m_crit); 378 bCouldRead = FALSE; 379 } 380 else 381 { 382 m_pPopList->reset(); 383 CSingleQueue<T> *pTemp = m_pPopList; 384 m_pPopList = m_pPushList; 385 m_pPushList = pTemp; 386 LeaveCriticalSection(&m_crit); 387 bCouldRead = TRUE; 388 } 389 } 390 if (bCouldRead) 391 { 392 return m_pPopList->popData(pData); 393 } 394 else 395 { 396 return FALSE; 397 } 398 } 399 400 template <class T> 401 void CDoubleQueue<T>::removeHead() 402 { 403 m_pPopList->removeHead(); 404 } 405 } 406 #endif
1 #include "dataqueue.h" 2 #include <process.h> 3 #include <assert.h> 4 5 using namespace hw; 6 using namespace std; 7 8 enum queueType {SIMPLEQ, SINGLEQ, DOUBLEQ, QUIT}; 9 10 #define QUEUE_SIZE_TEST 50 11 CSimpleQueue<int> g_simpleQ; 12 CSingleQueue<int> g_singleQ(QUEUE_SIZE_TEST); 13 CDoubleQueue<int> g_doubleQ; 14 15 int gWriteCnt_simple = 0; 16 int gReadCnt_simple = 0; 17 18 int gWriteCnt_single = 0; 19 int gReadCnt_single = 0; 20 21 int gWriteCnt_double = 0; 22 int gReadCnt_double = 0; 23 24 bool gReadThreadQuit = false; 25 bool gWriteThreadQuit = false; 26 27 void read(void *arg) 28 { 29 queueType type = (queueType)(*((queueType*)arg)); 30 31 while(!gReadThreadQuit) 32 { 33 if(type == SIMPLEQ) 34 { 35 int data = 0; 36 g_simpleQ.popData(data); 37 gReadCnt_simple++; 38 } 39 else if(type == SINGLEQ) 40 { 41 const int *pData = NULL; 42 g_singleQ.popData(pData); 43 g_singleQ.removeHead(); 44 gReadCnt_single++; 45 } 46 else if(type == DOUBLEQ) 47 { 48 const int *pData = NULL; 49 g_doubleQ.popData(pData); 50 g_doubleQ.removeHead(); 51 gReadCnt_double++; 52 } 53 else 54 { 55 assert(false); 56 break; 57 } 58 Sleep(10); 59 } 60 _endthread(); 61 } 62 63 void write(void *arg) 64 { 65 queueType type = (queueType)(*((queueType*)arg)); 66 67 while(!gWriteThreadQuit) 68 { 69 if(type == SIMPLEQ) 70 { 71 int data = 0; 72 g_simpleQ.pushData(data); 73 gWriteCnt_simple++; 74 } 75 else if(type == SINGLEQ) 76 { 77 const int data = 0; 78 g_singleQ.pushData(data); 79 gWriteCnt_single++; 80 } 81 else if(type == DOUBLEQ) 82 { 83 const int data = 0; 84 g_doubleQ.pushData(data); 85 gWriteCnt_double++; 86 } 87 else 88 { 89 assert(false); 90 break; 91 } 92 Sleep(10); 93 } 94 _endthread(); 95 } 96 97 void printUsage() 98 { 99 printf("usage:test.exe [option]\n \ 100 option: \ 101 0 use simple queue for test\n \ 102 1 use single queue for test\n \ 103 2 use double queue for test\n \ 104 3 quit\n\n"); 105 } 106 int main(int argc, char *argv[]) 107 { 108 printUsage(); 109 110 while(1) 111 { 112 int opt; 113 printf("please input the option number: "); 114 scanf_s("%1d", &opt); 115 if(opt == (int)SIMPLEQ) 116 { 117 118 } 119 else if(opt == (int)SINGLEQ) 120 { 121 122 } 123 else if(opt == (int)DOUBLEQ) 124 { 125 g_doubleQ.init(QUEUE_SIZE_TEST); 126 } 127 else if(opt == (int)QUIT) 128 { 129 break; 130 } 131 else 132 { 133 printf("invalid number\n"); 134 continue; 135 } 136 137 LARGE_INTEGER freq; 138 LARGE_INTEGER startCount, endCount; 139 QueryPerformanceFrequency(&freq); 140 QueryPerformanceCounter(&startCount); 141 142 HANDLE readHandle = (HANDLE)_beginthread(write, 0, &opt); 143 HANDLE writeHandle = (HANDLE)_beginthread(read, 0, &opt); 144 145 LONGLONG sec = 0; 146 /*!< run one second*/ 147 while((sec -1000) < 0.00001) 148 { 149 QueryPerformanceCounter(&endCount); 150 sec = (endCount.QuadPart - startCount.QuadPart) * 1000 / freq.QuadPart; 151 } 152 153 gReadThreadQuit = true; 154 gWriteThreadQuit = true; 155 156 WaitForSingleObject(readHandle, INFINITE); 157 WaitForSingleObject(writeHandle, INFINITE); 158 159 gReadThreadQuit = false; 160 gWriteThreadQuit = false; 161 162 int readCnt = 0; 163 int writeCnt = 0; 164 if ((queueType)opt == SIMPLEQ) 165 { 166 readCnt = gReadCnt_simple; 167 writeCnt = gWriteCnt_simple; 168 } 169 else if((queueType)opt == SINGLEQ) 170 { 171 readCnt = gReadCnt_single; 172 writeCnt = gWriteCnt_single; 173 } 174 else if((queueType)opt == DOUBLEQ) 175 { 176 readCnt = gReadCnt_double; 177 writeCnt = gWriteCnt_double; 178 } 179 printf("write count: %d, read count: %d\n", writeCnt, readCnt); 180 } 181 return 0; 182 }