stl库里面的list使用经历总结
来源:互联网 发布:优化后讨鬼传2psv画质 编辑:程序博客网 时间:2024/05/17 10:55
最近要用到c++标准库里面的list,但是它又不是支持多线程的。所以我决定对其进行一下改造,变成支持多线程的。
思路上面比较简单,模仿C#下面的模式,继承list,然后对用到的方法进行重载,加入lock,变成支持多线程的。实现的时候还是发现了很多问题,主要还是c++可怕的语法,搞了我好几天天。下面就总结一下。
首先为了简便,我就不继承了。
首先是类的声明:
template<class T>
class SyncList
{
public:
SyncList();
virtual ~SyncList();
bool empty();
T setTobegin();
T next();
bool end();
void push_front(const T& value);
void push_back(congst T& value);
void clear();
void remove(const T& value);
private:
list<T> _list;
pthread_mutex_t _mutex;
_List_iterator<T> head;
_List_iterator<T> tail;
};
这里面还是有些东西要说明一下的。首先push_front和push_back的声明,相信大家看着一定非常眼熟,因为那是我从stl的库里原样copy过来的,嘿嘿。然后是head和tail的类型——_List_iterator<T>。其实它就是list<T>::iterator。但是如果用iterator来声明head和tail的话,会编译不过去。我去查过list的头文件,看到里面有个typedef _List_iterator<_Tp> iterator。既然iterator不能用,那就用_List_iterator<T>好了。事实证明,这个果然可以用的,呵呵。
接下来,我说一下上面如此设计的思路。其实这个设计一点亮点都没有,或者说很屎吧。既然如此,还要说思路,主要就是为了总结一下对list的使用经验。
首先,因为这是一个支持多线程的list,因此遍历它的时候,我们不能像以前那样,调用begin,返回一个iterator,然后给iterator不断++,直到它等于end为止。这是因为,在我们遍历list的时候,另外一个线程很可能已经修改了这个list,随便给iterator++的话,你一定会像我刚开始那样——死得很惨。连续好几天在“段错误”里面徘徊,真的很容易让人短命!
因此,所有的iterator++操作,都要被封装在SyncList里面,这样才能尽量保证它没有问题。注意我说的是尽量。
基于上面的原因,这个SyncList就提供了个setTobegin功能,意思是告诉这个list,我要遍历你了,你把自己的head指向开头,tail指向结尾。下面是这个方法的代码:
template<class T>//因为声明和实现分开,所以在每个方法前面都要加这一行,很不爽是吧?我也是感觉这代码看起来很不爽。
T SyncList<T>::setTObegin()
{
T temp;//一定要声明一个局部变量,否则就无法支持多线程了。
pthread_mutex_lock(&_mutex);//加锁
head = _list.begin();//head指向开头
tail = _list.end();//tail指向结尾,注意结尾不是NULL,它真的是个尾巴呢。这是与.net类库里面不一样的地方,.net类库里面,尾巴是null
temp = *head;//取得head里面的数据
pthread_mutex_unlcok(&_mutex);//解锁
return temp;//设置好开头和结尾后,顺便返回头部的数据
}
既然可以开始了,那就得有个继续下去的道路,于是next方法又出现了:
template<class T>//每次都要把这行写一遍,太烦人了!!!
T SyncList<T>::next()
{
T temp;
pthread_mutex_lock(&_mutex);
head++;
temp = *head;
pthread_mutex_unlock(&_mutex);
return temp;
}
这里面其实藏着一个大问题,一个可以导致“段错误”的问题。所谓“段错误”,简单说,就是指针野了,引用了系统不让用的地方,然后出于保护的目的,程序会被系统直接挂掉,然后抛出一个“段错误”的异常。
那么隐患在哪里呢?就是那行head++!!!
可以看到,每次我调用next的时候,都会基于上次的位置,进行++操作,转到下一个。但是,如果,我突然调用了一下remove,正好删掉了当前的value,那现在的head就野了,再去调用就会出错了,大家可以试一下下面的代码,保证死得很壮烈:
list<T> ll;
list<T>::iterator current;
ll.push_back(100);
ll.push_back(200);
int a = *current;//ok,a是100
ll.remove(100);//current已经野了
current++;
a = *current;//error!不是200,而是崩溃
因此,为了避免这个问题,我改造了remove方法:
template<class T>
void SyncList<T>::remove(const T& value)
{
pthread_mutex_lock(&_mutex);
if (*head == value)//变化在这里,删除前判断一下,如果是当前的节点,就把当前节点后移一位
head++;//在本质上,相当于把head++和remove的顺序对换了一下。
_list.remove(value);
pthread_mutex_unlock(&_mutex);
}
如此一来,就可以避免“段错误”了。
下面是end方法的代码,用来判断是否到结尾了。
template<class T>
bool SyncList<T>::end()
{
bool temp = false;
pthread_mutex_lock(&_mutex);
if (head == tail)
temp = true;
else
temp = false;
pthread_mutex_unlock(&_mutex);
return temp;
}
此外,还要在构造函数和析构函数里面处理互锁的问题。
template<class T>
SyncList<T>::SyncList()
{
pthread_mutex_init(&_mutex);
}
template<class T>
SyncList<T>::~SyncList()
{
pthread_mutex_destory(&_mutex);
}
其他的方法,都很简单,就不多说了。
- stl库里面的list使用经历总结
- c++ stl list使用总结
- c++ stl list使用总结
- c++ stl list使用总结
- STL list的使用
- stl list的使用
- [STL] list的使用
- STL基础6:list容器的使用总结
- STL list 的相关总结
- STL标准模板库 list的使用
- stl之二: list使用总结【转】
- STL中list的使用
- STL中list的使用
- STL中list的使用:
- STL中list的使用
- STL中list的使用
- STL list容器的使用
- STL中list的使用
- BlackBerry通过全局变量的发送和接收来更新应用界面数据
- org.apache.commons.dbcp.BasicDataSource 资源包下载
- 点击按钮移动的div
- iocp(0)
- 《struts2权威指南》第21章拍卖系统案例的一处低级错误
- stl库里面的list使用经历总结
- VS程序性能分析器 -- 使用说明
- 主要邮件服务器地址
- 默写《标日》初,中级的perl脚本
- asp.net中循环访问控件组
- BS7799与ISO17799的发展历程
- Scrum对管理层的要求更高吗?再进一步,Agile对管理层的要求更高吗?
- windows版本的服务器端框架代码已经发布了。
- 熟悉 SMIL 2.0