如果线程必须写在同一个向量上,是不是可以使用线程

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&lt;int&gt; 而不是普通的 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 一次以将所有结果累积到其中。

以上是关于如果线程必须写在同一个向量上,是不是可以使用线程的主要内容,如果未能解决你的问题,请参考以下文章

超详细的JAVA多线程学习

Java多线程学习(吐血超详细总结)

Java开发需要注意的流程

OpenMP 子句共享与关键

通过线程使用向量单元

异步操作