您的位置:首页 > 编程语言 > C语言/C++

[C/C++标准库]_[初级]_[std::vector的多线程读写问题]

2015-08-07 18:49 435 查看
场景:

1. 有时候需要使用vector 或 map作为多线程的共享变量, map是tree结构, 读和写方法都不是线程安全的, 即同时读写会有崩溃的现象.

2. std::vector直观来说只用push_back和[] 下标访问操作应该没问题,push_back往后边加对象, 索引值只访问已经存储的变量(预先求size).注意, 这里不会删除vector元素.

可惜,这种多线程操作还是会崩溃. 单线程写和单线程读!!!

看代码:

test_vector.cpp

#include "gtest/gtest.h"
#include <vector>
#include <iostream>
#include <Windows.h>
#include "pthread.h"

class A
{
public:
A(int i):i_(i){}
int i_;
};

void* first = NULL;
void* second = NULL;

static void* Push(void* data)
{
std::vector<A*>& vec = *(std::vector<A*>*)data;
vec.push_back(new A(-1));
first = std::addressof(vec._Myfirst);
//std::cout << first << std::endl;
for(int i = 0; i< 100000;++i)
{
vec.push_back(new A(i));
//Sleep(2);
}
return NULL;
}

static void* Read(void* data)
{
std::vector<A*>& vec = *(std::vector<A*>*)data;
int size = vec.size();
while((size = vec.size())!= 100000)
{
for(int i = 0;i<size;++i)
{
A* a = vec[i];
second = std::addressof(vec._Myfirst);
std::cout << "a->i_: " << a->i_ << std::endl;
}
}
return NULL;
}

TEST(test_vector,testVector)
{
std::vector<A*> a;
pthread_t t1;
pthread_create(&t1,NULL,&Push,&a);
pthread_detach(t1);

pthread_t t2;
pthread_create(&t2,NULL,&Read,&a);
pthread_detach(t2);

system("pause");
}


运行几次,偶尔就会崩溃,size一直是比实际的个数小,通过查看debug变量值,奇怪的是a的值是无效的.


内存大小很正常:



崩溃的位置: a已经是无效的数值了.



看vector代码也没看出什么问题:

void push_back(_Ty&& _Val)
{	// insert element at end
if (_Inside(_STD addressof(_Val)))
{	// push back an element
size_type _Idx = _STD addressof(_Val) - this->_Myfirst;
if (this->_Mylast == this->_Myend)
_Reserve(1);
_Orphan_range(this->_Mylast, this->_Mylast);
_Cons_val(this->_Alval,
this->_Mylast,
_STD forward<_Ty>(this->_Myfirst[_Idx]));
++this->_Mylast;
}
else
{	// push back a non-element
if (this->_Mylast == this->_Myend)
_Reserve(1);
_Orphan_range(this->_Mylast, this->_Mylast);
_Cons_val(this->_Alval,
this->_Mylast,
_STD forward<_Ty>(_Val));
++this->_Mylast;
}
}


reference operator[](size_type _Pos)
{	// subscript mutable sequence
#if _ITERATOR_DEBUG_LEVEL == 2
if (size() <= _Pos)
{	// report error
_DEBUG_ERROR("vector subscript out of range");
_SCL_SECURE_OUT_OF_RANGE;
}

#elif _ITERATOR_DEBUG_LEVEL == 1
_SCL_SECURE_VALIDATE_RANGE(_Pos < size());
#endif /* _ITERATOR_DEBUG_LEVEL */

return (*(this->_Myfirst + _Pos));
}

目前还没找到原因,有一种可能是this->-Myfirst的值debug时没有变化,不是它的问题, 那可能就是pointer对象在改变容量时改变了对象的存储位置,时间关系没有深入研究.

环境:

visual studio c++ 2010 sp1.

作为临时解决方案, 暂时用C数组来解决这个push_back和下标访问的问题,

test_carray.cpp

#include "gtest/gtest.h"
#include <vector>
#include <iostream>
#include <Windows.h>
#include "pthread.h"

class A
{
public:
A(int i):i_(i){}
int i_;
};

class S
{
public:
S()
{
index_ = 0;
count_ = sizeof(a)/sizeof(A*);
}
A* a[10000];
int index_;
int count_;
};

static void* Push(void* data)
{
S* s = (S*)data;
for(int i = 0; i< s->count_;++i)
{
s->a[i] = new A(i);
s->index_ = i;
//Sleep(2);
}
s->index_+=1;
return NULL;
}

static void* Read(void* data)
{
S* s = (S*)data;
int size = 0;
while((size = s->index_) < s->count_)
{
for(int i = 0;i<size;++i)
{
A* a = s->a[i];
std::cout << "a->i_: " << a->i_ << std::endl;
}
}
return NULL;
}

TEST(test_carray,testArray)
{
S s;
pthread_t t1;
pthread_create(&t1,NULL,&Push,&s);
pthread_detach(t1);

pthread_t t2;
pthread_create(&t2,NULL,&Read,&s);
pthread_detach(t2);

pthread_t t3;
pthread_create(&t3,NULL,&Read,&s);
pthread_detach(t3);
system("pause");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: