C ++多线程和向量 [英] C++ multiple threads and vectors
问题描述
我尝试了以下算法的各种实现,但总是在程序运行一段时间后崩溃。
我有一个基础对象
class Element
{
public:
int a;
float p;
Element(int _a,float _p = 1.0):a(_a),p(_p){};
};
其中我创建一个向量并包含在一个Buffer对象中。
class Buffer
{
public:
Buffer(){};
vector< Element>生的;
vector< Element>优化; // DATA CALCULATED BASED ON RAW
void addElement(int _a,float _p = 1.0)//填充RAW缓冲区
{
raw.push_back(Element(_a,_p ));
}
void compute()//计算优化缓冲区
{
float t;
int i;
for(std :: vector< Element> :: iterator it = raw.begin(); it!= raw.end(); ++ it)
{
optimised.push_back元素(it-> a,it-> p));
//对于(i = 1; i <9999999; i ++)
t = 9./i进行一些计算强制计算;
}
};
void clear()//删除两个缓冲区
{
raw.clear();
optimised.clear();
}
};
我有一个声明一个Buffer对象 - 负责捕获当前数据流 - 和一个向量的缓冲区对象 - 表现得像以前创建的缓冲区的历史/队列。
vector< Buffer>队列;
主线程负责填充缓冲区对象,一旦系列完成,进入队列。
一旦一个新的缓冲区被添加到队列,一个Compute()函数被调用在一个单独的线程来分析最近提交的数据。
//将当前缓冲区添加到队列
queue.push_back(buffer);
//在并行缓冲区中运行'COMPUTE'/背景在最后提交的缓冲区
std :: thread t(& Buffer :: compute,& queue.back());
t.detach();
//清除缓冲区,准备新的系列
buffer.clear();
程序完全正常,它在执行过程中崩溃(有时只是提交一个缓冲区后,有时在几个...之后,如果队列中一次只有一个缓冲区,它通常工作更长)。
在这种情况下我需要使用互斥锁吗?如果是,在哪里?
您有什么建议如何优化数据收集它进入队列) - 我认为AddElement()有点不必要的昂贵?
任何帮助请求!
谢谢
问题是& queue [last] c $ c>。这给你一个指针,指向向量当前存储缓冲区的位置。如果向量重新分配(
push_back
可以这样做),则指针无效。
$ <$ c
$ b
- 将指针存储在
队列
向量中。像向量< unique_ptr<缓冲区>>
- 使用不会使指针无效的数据结构在修改时失效。
- 重新分配。您最初可以执行
resize(x)
,然后跟踪最后一个自己。
list
和 deque
将会正常工作。 更新:添加代码示例。在Coliru上编译和运行( http://coliru.stacked-crooked.com/ )
#include< memory>
#include< vector>
#include< iostream>
class Buffer {};
int main()
{
std :: unique_ptr< Buffer> buffer {new Buffer()};
std :: vector< std :: unique_ptr< Buffer>>队列;
for(int i = 0; i <10; i ++){
buffer.reset(new Buffer());
//做事情缓冲;
queue.push_back(move(buffer));
}
std :: cout<< queue.size()<< std :: endl;
}
I tried various implementations of the following algorithm but always ended up with a crash after a while the program runs...
I have a base object
class Element
{
public:
int a;
float p;
Element(int _a, float _p=1.0): a(_a), p(_p){};
};
of which I create a vector and include in a Buffer object.
class Buffer
{
public:
Buffer(){};
vector<Element> raw;
vector<Element> optimised; // DATA CALCULATED BASED ON RAW
void addElement(int _a,float _p=1.0) // FILL THE RAW BUFFER
{
raw.push_back(Element(_a,_p));
}
void compute() // COMPUTE THE OPTIMISED BUFFER
{
float t;
int i;
for(std::vector<Element>::iterator it = raw.begin(); it != raw.end(); ++it)
{
optimised.push_back(Element(it->a,it->p));
// DO SOME COMPUTATIONALLY INTENSIVE CALCULATIONS
for(i=1; i<9999999; i++)
t = 9./i;
}
};
void clear() // ERASE BOTH BUFFERS
{
raw.clear();
optimised.clear();
}
};
I have a declaration of a single Buffer object - responsible for capturing the current data stream - and a vector of Buffer objects - behaving like a history/queue of the previously created buffers.
Buffer buffer;
vector<Buffer> queue;
The main thread is responsible of filling the buffer object and - once a series is complete - submit the buffer into the queue. As soon as a new buffer is added to the queue a Compute() function is called on a separate thread to analyse the recently submitted data.
//ADD THE CURRENT BUFFER TO THE QUEUE
queue.push_back(buffer);
//RUN 'COMPUTE' IN PARALLEL/BACKGROUND ON THE LAST SUBMITTED BUFFER
std::thread t(&Buffer::compute, &queue.back());
t.detach();
//CLEAR THE BUFFER, READY FOR A NEW SERIES
buffer.clear();
The program complies fine and launches but it crashes during execution (sometimes after just one buffer is submitted, sometimes after a few... it generally 'works for longer' if there is only one buffer at a time in the queue).
Do I need to use mutex locks in this situation ? If so, where ?
Do you have any suggestion on how to optimise the collection of the data (fill the 'buffer' object and submit it into the queue) - I think AddElement() is a bit unnecessarily expensive ?
ANY HELP APPRECIATED!
Thanks
The problem is with &queue[last]
. That gives you a pointer to where the vector currently stores the buffer. If vector reallocates (push_back
can do that), then the pointer is invalid.
There are a few solutions to this:
- Store pointer in the
queue
vector. Something likevector<unique_ptr<Buffer>> queue
will work (and makes sure you don't accidentally leak the memory). - Use a datastructure that will not invalidate invalidate the pointers when modified.
list
anddeque
will work. - Make sure the vector doesn't reallocate. You can do a
resize(x)
initially, and then keep track of the last yourself.
Update: Add a code sample. This compiles and runs fine on Coliru (http://coliru.stacked-crooked.com/)
#include <memory>
#include <vector>
#include <iostream>
class Buffer {};
int main()
{
std::unique_ptr<Buffer> buffer {new Buffer()};
std::vector<std::unique_ptr<Buffer>> queue;
for (int i = 0; i < 10; i++) {
buffer.reset(new Buffer());
// Do things to buffer;
queue.push_back(move(buffer));
}
std::cout << queue.size() << std::endl;
}
这篇关于C ++多线程和向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!