//
// 功能:T类型必须实现‘=’操作符
//
// must one-writer and maybe multi-readers
//
template <typename T>
class TSCOMMON_EXPORT CBigList
{
private:
struct Node
{
T data;
Node* prev;
Node* next;
};
public:
explicit CBigList(int size=DEFAULT_ARRAY_SIZE)
: size_(size > 0 ? size : DEFAULT_ARRAY_SIZE)
, buffer_(new Node[size_])
, head_(NULL)
, tail_(NULL)
, tail_prev_(NULL)
{
memset(buffer_, 0, sizeof(Node)*size_);
}
virtual ~CBigList()
{
if (buffer_)
{
delete buffer_;
}
}
// Don't call this function in multi-threads.
void push_back(T* pData)
{
if (pData)
{
tail_prev_ = tail_;
mutex_.lock();
if (tail_)
{
Node* pCur = tail_+1;
tail_->next = pCur;
pCur->prev = tail_;
pCur->data = *pData;
pCur->next = NULL;
tail_ = pCur;
#ifdef WIN32
assert (tail_ != head_);
#endif
}
else
{
tail_ = buffer_;
tail_->data = *pData;
tail_->prev = NULL;
tail_->next = NULL;
head_ = buffer_;
}
mutex_.unlock();
}
else
{
return ;
}
}
void push_front(T* pData)
{
if (pData)
{
tail_prev_ = tail_;ddd
mutex_.lock();
Node* pCur = getHeadPrev();
if (head_)
{
pCur->data = *pData;
pCur->next = head_;
head_->prev = pCur;
pCur->prev = NULL;
head_ = pCur;
#ifdef WIN32
assert(tail_ != head_);
#endif
}
else
{
pCur->data = *pData;
pCur->next = tail_;
pCur->prev = head_;
head_ = pCur;
tail_ = pCur;
}
mutex_.unlock();
}
else
{
return ;
}
}
T* get_current_ptr()
{
bool bRet = mutex_.tryLock();
if (bRet) // At this moment,neither is updating the current node.
{
if (tail_)
{
T* data = &tail_->data;
mutex_.unlock();
return data;
}
else
{
mutex_.unlock();
return NULL;
}
}
else // now other thread is updating the current node(tail_), in order to get the newest node, we get the current node previous.
{
Node* pNode = tail_prev_;
if (pNode)
{
T* data = &pNode->data;
//mutex_.unlock(); // zl 2013/08/08 when tryLock() return 0, mutex_ is not locked.so, don't lock here.
return data;
}
else
{
//mutex_.unlock();
return NULL;
}
}
}
T* get_data() // loop from the start position
{
//current_mutex_.lock();
/* 2013/08/10 add TLS start */
#ifdef WIN32
static __declspec(thread) Node* pCurrent = NULL;
#elif defined __GNUG__
static __thread Node* pCurrent = NULL;
#endif
/* 2013/08/10 add TLS end */
bool bRet = false;
if (pCurrent)
{
mutex_.lock();
pCurrent = pCurrent->next;
if (pCurrent)
{
T* data = &pCurrent->data;
//current_mutex_.unlock();
mutex_.unlock();
return data;
}
else
{
mutex_.unlock();
return NULL;
}
}
else // first time
{
if (head_)
{
mutex_.lock();
pCurrent = head_;
mutex_.unlock();
T* data = &pCurrent->data;
//current_mutex_.unlock();
return data;
}
else
{
//current_mutex_.unlock();
return NULL;
}
}
}
private:
// judge the data whether in the range.
bool assertInRange(Node* data)
{
if (head_ && tail_) // the list has member
{
if (&head_ >= &tail_) // head is previous the tail
{
if ((data >= buffer_ && data <= &tail_)
|| (data >= &head_ && data <= buffer_+size_-1))
{
return true;
}
else
{
#if WIN32
assert(0);
#endif
return false;
}
}
else // tail is previous the head
{
if (data >= &head_ && data <= &tail_)
{
return true;
}
else
{
#if WIN32
assert(0);
#endif
return false;
}
}
}
else if (!head_ || !tail_) // the list has not any member
{
#if WIN32
assert(1);
#endif
return false;
}
}
Node* getHeadPrev()
{
Node* pCur = NULL;
if (head_)
{
if (head_ != buffer_) {
pCur = head_-1;
#ifdef WIN32
assert(pCur != tail_);
#endif
} else {
pCur = buffer_+size_-1;
}
}
else
{
pCur = buffer_;
}
return pCur;
}
private:
CBigList(const CBigList&);
CBigList& operator=(const CBigList &);
private:
int size_;
Node* const buffer_;
Node* head_;
Node* tail_;
Node* tail_prev_;
Mutex mutex_;
/* 2013/08/10 comment. add TLS, so there is no need to use lock start */
//Mutex current_mutex_;
/* 2013/08/10 comment. add TLS, so there is no need to use lock end */
};
BigList
最新推荐文章于 2024-08-21 10:09:26 发布