三种数据队列的实现

 

  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 }

 

 

参考:https://software.intel.com/zh-cn/blogs/2013/03/21/twoqueues/?utm_campaign=CSDN&utm_source=intel.csdn.net&utm_medium=Link&utm_content=%20Multicore%20%e2%80%93%20TwoQueues

你可能感兴趣的:(队列)