原因
在项目中前人使用了std::list来做一个队列式,支持头或者尾的push操作。使用场景是视频的录制:
生产者:从摄像头采集数据,然后push_front到队列头,如果超过了最大限制,则pop_back队列尾的元素,实现丢帧操作
消费者:从队列里面back拿到桢,然后pop_back删除末尾桢。
所有的list的操作均加入了互斥锁。理论上应该是没有多线程访问的问题的。然而在线上表现却在back拿数据的时候有极少数的Crash。在拿数据前我还用empty方法判断肯定不为空的。只能认为是list内部实现可能有问题。也有可能是自己使用姿势不对吧。能力有限,看std::list的实现也看不出什么问题。在看源码的过程中,发现stl::list的size()的实现居然是O(n)复杂度,搜了下原因是为了O(1)的去实现transfer方法,便于做sort, merge等操作。基于这些问题,我决定还是自己写一个类似的数据结构,出了问题也好修复。于是就写了如下双向链表。
//
// Created by tao on 2018/3/1.
//
#pragma once
#include <atomic>
#define EXCEPTION_EMPTY_LIST 1
template<typename T>
struct Node {
T _data;
Node<T> *_next;
Node<T> *_prev;
};
template<typename T>
class SimpleList {
private:
Node<T> *m_pHead;
Node<T> *m_pTail;
size_t m_iSize;
public:
SimpleList() : m_pHead(nullptr),
m_pTail(nullptr),
m_iSize(0) {}
void push_back(T x);
void push_front(T x);
T back() throw(int);
T front();
void pop_back();
void pop_front();
inline int size() {
return m_iSize;
}
inline bool empty() {
return m_iSize == 0;
}
~SimpleList() {
Node<T> *cur = m_pHead;
while (cur != nullptr) {
Node<T> *next = cur->_next;
delete cur;
cur = next;
if (cur == nullptr) {
break;
}
}
}
};
template<typename T>
void SimpleList<T>::push_back(T x) {
Node<T> *pNewNode = new Node<T>[sizeof(Node<T>)];
pNewNode->_data = x;
pNewNode->_next = nullptr;
pNewNode->_prev = nullptr;
if (m_pHead == nullptr) {
m_pHead = pNewNode;
m_pHead->_prev = nullptr;
m_pHead->_next = nullptr;
m_pTail = m_pHead;
} else {
Node<T> *pCurrentNode = m_pTail;
pCurrentNode->_next = pNewNode;
pNewNode->_prev = pCurrentNode;
m_pTail = pNewNode;
}
m_iSize++;
}
template<typename T>
T SimpleList<T>::back() throw(int) {
if (m_pTail) {
return m_pTail->_data;
}
throw EXCEPTION_EMPTY_LIST;
}
template<typename T>
T SimpleList<T>::front() {
if (m_pHead) {
return m_pHead->_data;
}
throw EXCEPTION_EMPTY_LIST;
}
template<typename T>
void SimpleList<T>::pop_back() {
if (m_pTail) {
if (m_pTail->_prev == nullptr) {
delete m_pTail;
m_pTail = nullptr;
m_pHead = nullptr;
} else {
Node<T> *del = m_pTail;
m_pTail = m_pTail->_prev;
m_pTail->_next = nullptr;
delete del;
del = nullptr;
}
m_iSize--;
}
}
template<typename T>
void SimpleList<T>::push_front(T x) {
Node<T> *pNewNode = new Node<T>[sizeof(Node<T>)];
pNewNode->_data = x;
pNewNode->_next = m_pHead;
pNewNode->_prev = nullptr;
if (m_pHead != nullptr) {
m_pHead->_prev = pNewNode;
}
m_pHead = pNewNode;
if (m_pTail == nullptr) {
m_pTail = m_pHead;
m_pTail->_prev = nullptr;
m_pTail->_next = nullptr;
}
m_iSize++;
}
template<typename T>
void SimpleList<T>::pop_front() {
if (m_pHead != nullptr) {
if (m_pHead->_next == nullptr) {
delete m_pHead;
m_pHead = nullptr;
m_pTail = nullptr;
} else {
Node<T> *del = m_pHead;
m_pHead = m_pHead->_next;
m_pHead->_prev = nullptr;
delete del;
del = nullptr;
}
m_iSize--;
}
}