如果线程必须写在同一个向量上,是不是可以使用线程
Posted
技术标签:
【中文标题】如果线程必须写在同一个向量上,是不是可以使用线程【英文标题】:Is it possible to use threads if they have to write on the same vector如果线程必须写在同一个向量上,是否可以使用线程 【发布时间】:2016-12-12 13:32:03 【问题描述】:我必须用 SDE 求解热方程。 程序运行正常,但速度很慢。
简而言之:我写了一个程序,在一个向量上随机设置许多粒子并将它们移动一些时间步长。
在时间 t 之后,计算每个网格箱中的所有粒子并将该数字保存在计数向量中。现在我必须做runs
=1000 以获得好的结果。 (函数属于一个类)。
void makeruns(const int runs)
for(int i=0; i<runs; ++i)
setandmove();
void setandmove()
for(int t=0; t<timesteps; ++t)
//set new particles and move particles on the grid
//Endposition is saved in the list Y_omega
//count number of points in bins
for(auto it=Y_omega.begin(); it!=Y_omega.end(); ++it)
double valf = it->first;
double vals = it->second;
auto it_f = std::lower_bound(intervall.begin(),intervall.end(),valf, [](auto P, auto V) -> bool return P< V;);
auto it_s = std::lower_bound(intervall.begin(),intervall.end(),vals, [](auto P, auto V) -> bool return P < V;);
int dist1 = std::distance(intervall.begin(),it_f);
int dist2 = std::distance(intervall.begin(),it_s);
count.at(dist1 + s*dist2)=count.at(dist1 + s*dist2) + 1;
Y_omega.clear();
是否可以创建线程,至少在第一部分中,或者当它们在向量count
上写入时它们会发生冲突
std::thread t1(makeruns, 250);
std::thread t2(makeruns, 250);
std::thread t3(makeruns, 250);
std::thread t4(makeruns, 250);
t4.join();
t3.join();
t2.join();
t1.join();
遗憾的是我不精通线程。
【问题讨论】:
是的,这是可能的。但是,您必须同步访问。这可能最终不会给您带来任何性能提升。 相关:***.com/questions/41068201/… 线程是引入细微错误的好方法。因此,值得尝试使事情尽可能简单,足够简单以至于很明显不会有错误。注意:如果线程都很忙,那么拥有比机器上的内核更多的线程没有任何好处(这就是你正在做的)。我建议让每个线程都有它自己的自己的网格和计数数组——然后在运行结束时,抓取一个互斥体,快速将本地计数添加到全局计数中,然后释放互斥体。 从消除代码中的噪音开始。使用 lambda 对lower_bound
的调用与在没有函数对象的情况下调用 lower_bound
完全相同。 count.at(dist1 + s*dist2)=count.at(dist1 + s*dist2) + 1;
可以简单地为 ++count[dist1 + s*dist2];
当然,你可以调用魔法编译器来消除这里的浪费,但如果你不把它放在开头,那么你就知道它不存在。
从代码中我找不到需要与问题的 4 个实例共享的向量。是不是只有counting-vector需要共享?
【参考方案1】:
如果多个线程要读取和写入相同的数据位置,代码必须同步这些访问。否则行为未定义。
正如 Martin Bonner 在注释中提到的,一种方法是让每个线程分别保存自己的统计信息,并在最后合并各种线程结果。
另一种方法是使用原子变量。如果 count
数组包含 std::atomic<int>
而不是普通的 int
(或您的实际计数数据类型),那么编写的代码只需稍作更改即可正常工作:替换
count.at(dist1 + s*dist2)=count.at(dist1 + s*dist2) + 1;
与
++count.at(dist1 + s*dist2);
或
++count[dist1 + s*dist2];
选择采用哪种方法在很大程度上取决于正在处理的数据的性质。
【讨论】:
@TobySpeight -- 很好,谢谢。我在对该问题的评论中提到了这一点,但应该在这里提及。固定。【参考方案2】:如果您在每次计算后使用向量插入结果,您需要确保一次只有一个线程对向量执行插入操作。由于插入操作不是很复杂,插入时阻塞其他线程不会有时间损失。
最好的方法是使用互斥对象;
std::mutex m; // may be a global object or may be shared by a using a pointer.
Vector counting_vector; //some vector object for keeping result of each computation.
void threadWorker(int count)
//here
//create vector that will be used for set and move operation. Each thread will have it's own vector.
while(count-->0)
//perform the set and move operation on the vector;
result=;/*the computed result*/
m.lock();
//code between lock() and unlock() won't run concurrently.
counting_vector.insert(result);//insert or push_back into the vector
m.unlock();
【讨论】:
您可以通过将结果累积到每个线程向量中来减少争用,然后锁定counting_vector
一次以将所有结果累积到其中。以上是关于如果线程必须写在同一个向量上,是不是可以使用线程的主要内容,如果未能解决你的问题,请参考以下文章