标签:style blog http io ar color os 使用 sp
我们知道,对于一个队列而言,最主要的两个操作是添加元素(Add)和获取/删除元素(Get),之前文章中实现了一个linux下通用的阻塞队列BlockQueue,通过代码可以看出,为了保证在多线程环境下安全正确的运行,BlockQueue定义中的几个关键函数都进行了加锁保护,而锁住的对象是整个队列,加锁粒度较大。当交易量增大,线程数增长时,会对性能产生一定的影响:同一时刻只能有一个线程添加或获取元素,而其他线程都需要等待。
队列的特性在于它只允许在表的头部(head)进行删除操作,而在表的尾部(tail)进行插入操作,根据这个特性,我们可以认为这两个操作其实是不冲突的,毕竟一个在头一个在尾,那么如果我们使用两个锁,head lock和tail lock,分别在处理插入和删除时对队列进行加锁,使插入和删除操作互不影响,而不是两个操作使用同一个锁,锁住整个队列,这样,同一时刻可以有两个线程对队列分别进行插入和删除操作,可以使性能得到一定提高。分析代码中的Add和Get函数,发现在向空队列中插入第一个元素和获取(删除)最后一个元素时,需要同时操作head和tail指针,按照之前的说法,就要同时获取队列的head lock和tail lock,这里使得程序更加复杂,因为如果加锁顺序错误,很容易出现死锁,而即便能够写出正确的代码,每次操作进行两次加锁解锁,同样会使性能下降。
那么如何才能像上文那样使用head lock和tail lock来提高程序的性能呢,其实这个算法已经被实现,它很巧妙的在队列构造时,将head和tail指针指向了同一个data域为空的头结点,根据此算法,对上文中的BlockQueue进行修改:
1 template<class T> 2 class BlockQueue 3 { 4 public: 5 BlockQueue(); 6 ~BlockQueue(); 7 8 void Add(T *pData); 9 T *Get(int timeout=0); 10 void SetBlockFlag(int nBlockFlag); 11 private: 12 typedef struct _Node 13 { 14 T * m_pData; 15 struct _Node * m_pNext; 16 } Node; 17 Node * m_pHead; 18 Node * m_pTail; 19 20 bool m_bBlockFlag; //是否阻塞 21 CMutex m_cHeadLock; //头部锁 22 CMutex m_cTailLock; //尾部锁 23 CCond m_condQueue; 24 }; 25 26 template<class T> 27 BlockQueue<class T>::BlockQueue() 28 { 29 Node *pTrivial = new Node; 30 pTrivial->m_pData = NULL; 31 pTrivial->m_pNext = NULL; 32 m_pHead = m_pTail = pTrivial; 33 34 m_bBlockFlag = false; 35 } 36 37 template<class T> 38 void BlockQueue<class T>::SetBlockFlag() 39 { 40 m_bBlockFlag = false; 41 } 42 43 template<class T> 44 BlockQueue<class T>::~BlockQueue() 45 { 46 Node *pTmp = NULL; 47 while (m_pHead != NULL) 48 { 49 pTmp = m_pHead; 50 m_pHead = m_pHead->m_pNext; 51 delete pTmp; 52 pTmp = NULL; 53 } 54 m_pTail = NULL; 55 } 56 57 template<class T> 58 void BlockQueue<class T>::Add(T *pData) 59 { 60 Node *pTmp = new Node; 61 pTmp->m_pData = pData; 62 pTmp->m_pNext = NULL; 63 64 m_cTailLock.EnterMutex(); 65 m_pTail->m_pNext = pTmp; 66 m_pTail = pTmp; 67 68 if(m_bBlockFlag) 69 m_condQueue.Signal(); 70 71 m_cTailLock.LeaveMutex(); 72 } 73 74 template<class T> 75 T *BlockQueue<class T>::Get(int timeout) 76 { 77 m_cHeadLock.EnterMutex(); 78 while (m_pHead->m_pNext == NULL) 79 { 80 if (!m_bBlockFlag) 81 { 82 m_cHeadLock.LeaveMutex(); 83 return NULL; 84 } 85 else 86 { 87 if (m_condQueue.WaitLock(m_cHeadLock.GetMutex()) == 1) 88 { 89 m_cHeadLock.LeaveMutex(); 90 return NULL; 91 } 92 } 93 } 94 95 Node * pTmp = m_pHead; 96 Node * pNewHead = pTmp->next; 97 T *pTmpData = pNewHead->m_pData; 98 m_pHead = pNewHead; 99 100 m_cHeadLock.LeaveMutex(); 101 102 delete pTmp; 103 pTmp = NULL; 104 105 return pTmpData; 106 }
与之前版本的代码进行对比:
用图来描述描述队列的创建,添加元素和删除元素:
未完待续……
标签:style blog http io ar color os 使用 sp
原文地址:http://www.cnblogs.com/Tour/p/4108521.html