Попробовал Relacy Race Detector. Либа оправдала все ожидания - сходу нашла 1 баг в pop_front:
#include "windows.h"
template<class Type>
Type * Exchange(Type ** ppDestination, Type * pData)
{
return (Type * )InterlockedExchangePointer((void**)ppDestination, pData);
}
struct BaseNode
{
BaseNode * pNext;
BaseNode()
: pNext(0)
{
}
private:
BaseNode(const BaseNode &);
BaseNode & operator = (const BaseNode &);
};
template<class Type>
struct ValueNode:public BaseNode
{
Type value;
public:
ValueNode(Type obj = 0)
: value(obj)
{
}
~ValueNode()
{
}
};
template <class NodeType>
class CList
{
CList(const CList &);
CList & operator = (const CList &);
BaseNode m_processingNode;
BaseNode m_fakeNode;
BaseNode * m_pFirst;
BaseNode * m_pLast;
long m_fakeNodeAdded;
protected:
void push_back_impl(BaseNode * pNode)
{
BaseNode * pRealLast = Exchange(&m_pLast, pNode);
// if pRealLast is fakenode, only after that node will be ready to be fetched:
pRealLast->pNext = pNode;
}
bool pop_front_impl(BaseNode ** ppNode)
{
*ppNode = 0;
while(1)
{
// take a first node
BaseNode * pFirst = Exchange(&m_pFirst, &m_processingNode);
if (pFirst == &m_processingNode)
continue;
// pFirst is valid
if (!pFirst->pNext)
{
// there is no second element
if (pFirst == &m_fakeNode)
{
// cleanup
Exchange(&m_pFirst, pFirst);
return false;
}
// push back fake node
if (InterlockedIncrement(&m_fakeNodeAdded) != 1)
{
InterlockedDecrement(&m_fakeNodeAdded);
// cleanup
Exchange(&m_pFirst, pFirst);
continue;
}
push_back_impl(&m_fakeNode);
// still not added
if (!pFirst->pNext)
{
// cleanup
Exchange(&m_pFirst, pFirst);
continue;
}
}
*ppNode = pFirst;
Exchange(&m_pFirst, pFirst->pNext);
pFirst->pNext = 0;
return true;
}
}
public:
CList()
: m_pFirst(0), m_pLast(0), m_fakeNodeAdded(1)
{
m_pFirst = m_pLast = &m_fakeNode;
}
// interface:
void push_back(NodeType * pNode)
{
push_back_impl(pNode);
}
bool pop_front(NodeType ** pNode)
{
while(1)
{
bool res = pop_front_impl((BaseNode **)pNode);
if (!res)
return res;
if (*pNode != &m_fakeNode)
{
return res;
}
InterlockedDecrement(&m_fakeNodeAdded);
}
}
};
Действительно, довольно дурацкий ляп - pop_front_impl может вернуть &m_fakeNode и во второй раз, нужно вызывать ее в цикле. В остальном все вроде бы ок, больше багов нет.
З.Ы. Похоже, фреймворк вправду крут.
No comments:
Post a Comment