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

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

2015-08-07 18:49 525 查看
场景:
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");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: