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

场景:

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");
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-14 20:55:22

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

【python标准库学习】thread,threading(二)多线程同步

继上一篇介绍了python的多线程和基本用法.也说到了python中多线程中的同步锁,这篇就来看看python中的多线程同步问题. 有时候很多个线程同时对一个资源进行修改,这个时候就容易发生错误,看看这个最简单的程序: import thread, time count = 0 def addCount(): global count for i in range(100000): count += 1 for i in range(10): thread.start_new_thread(ad

【python标准库学习】thread,threading(一)多线程的介绍和使用

在单个程序中我们经常用多线程来处理不同的工作,尤其是有的工作需要等,那么我们会新建一个线程去等然后执行某些操作,当做完事后线程退出被回收.当一个程序运行时,就会有一个进程被系统所创建,同时也会有一个线程运行,这个线程就是主线程main,在主线程中所创建的新的线程都是子线程,子线程通常都是做一些辅助的事.python中提供了thread和threading两个模块来支持多线程. python中使用线程有两种方式,第一种是用thread模块的start_new_thread函数,另一种是用threa

[C/C++标准库]_[初级]_[交集和补集]

场景: 1. 计算std::vector A和 std::vector B里的相同的元素, 用于保留不删除. 2. 计算std::vector A和 std::vector B里各自的补集, 用于删除A的补集和添加B的补集,用在一些更新关联表的操作里. 比如联系人A所属分组B是一个集合BV, 把联系人A的所属分组 修改为集合CV, 就需要删除两个集合BV,CV的CV补集和新增BV补集. 3. C++标准库为我们提供了这些算法. 代码: // test_AndroidAssistant.cpp :

[C/C++标准库]_[初级]_[使用模板删除字符串前后空格((w)string space)]

场景: 1. C++没有提供删除std::(w)string的前后空格的函数,比如TrimSpace. 2. 很多库都提供, 但是为了移植代码方便,最好还是能用标准库解决就用标准库. 下边用模板实现了移除空格的函数. test.cpp #include <iostream> #include <stdlib.h> #include <string.h> #include <string> #include <ctype.h> using name

[C/C++标准库]_[初级]_[使用ctype里的isxxx函数时要注意的事项]

场景: 1. 标准库里的 ctype.h里的函数是用于1个字节的判断的,但是参数却是int, 这样很容易导致误用. isalpha iscntrl isdigit isgraph isprint ispunct isspace isxdigit isalnum islower isupper int isspace( int ch ); 最恶心的是vc++的实现会对超过1字节的值会直接崩溃,gcc不会!!! #if defined (_DEBUG) extern "C" int __c

[C/C++]_[初级]_[使用zlib库压缩文件]

场景: 1. WIndows上没找到系统提供的win32 api来生成zip压缩文件, 有知道的大牛麻烦留个言. 2. zlib比较常用,编译也方便,使用它来做压缩吧.MacOSX平台默认支持zlib库. http://zlib.net 3. zlib库里的 src\contrib\minizip\minizip.c  里有压缩例子, 我现在使用的是zlib 1.2.5,用vs2010编译完.下载地址: http://download.csdn.net/detail/infoworld/8177

[C/C++不常见语法特性]_[初级]_[左值-右值-lvalue-rvalue]

参考:1. http://en.cppreference.com/w/cpp/language/value_category   << Value categories >> 2. https://msdn.microsoft.com/en-us/library/dd293668.aspx   << Rvalue Reference Declarator: && >>3. https://msdn.microsoft.com/en-us/li

[zlib]_[初级]_[使用Zlib完整解压zip内容]

场景: 1. 解压文件一般用在下载了一个zip文件之后解压,或者分析某个文件需要解压的操作上. 2. 解压文件,特别是解压带文件夹的zip文件往往系统没有提供这类Win32 API,当然C#自带库能解压, 当然这里只讨论C/C++, 像C#和Java这种开挂的标准库不在考虑范围内. 3. zlib解压文件的使用例子在 contrib\minizip 例子里. 这里基本是直接提取miniunz.c 的代码进行封装解压即可, 只是改了下支持中文路径. 主文件 zip_util.cpp #includ

[WTL/ATL]_[初级]_[如何使用GetOpenFileName多选文件-根据文件名长度计算lpstrFile长度]

场景: 1. 使用GetOpenFileName 时, 需要预先自定义lpstrFile的长度比如,buf[1024], 但是如果选择的文件过多怎么办?总不能创建一个超大的内存空间吧, 如果选择少时又浪费内存. 2. 微软的MSDN的坏处就是不提供实际的例子,而在别的地方提供,难道他们没遇到这类普通的问题? 3. 这里stackoverflow提供了一个微软使用lpfnHook 的例子来解决这个问题,这个例子对于unicode是有问题的,计算长度没有x2. 这个bug困扰了我半天. 找这个解决方