首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用线程求和向量中的值

使用线程求和向量中的值
EN

Code Review用户
提问于 2014-03-27 23:23:22
回答 1查看 5.8K关注 0票数 16

这是我第一个使用线程的程序。我使用C++11标准线程,并在Linux上运行它。

该程序创建两个线程,将向量中的所有元素相加在一起。第一个创建的线程与向量的左侧和,另一个线程与向量的右侧和。

主线程运行到两者都完成为止,将两个和相加在一起,然后打印和。

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <thread>

void
adder( const std::vector<int> & v, int begin, int end, int & result)
{
  for( ; begin < end; ++begin )
    {
      result = result + v.at( begin );
    }
}

int
main()
{
  int sum_left  = 0;
  int sum_right = 0;


  std::vector<int> v( 100000000,1); //100 millions
  int v_size = v.size();

  std::thread t1( adder, v, 0,v_size/2 , std::ref(sum_left) );
  std::thread t2( adder, v, v_size/2, v_size, std::ref(sum_right) );

  t1.join();
  t2.join();

  int sum_total = sum_left + sum_right;

  std::cout << sum_total << '\n';

  return 0;
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2014-03-28 01:02:45

首先,这是第一次很好地尝试编写一些线程代码。主要的症结在于您正在传入一个int &并返回void。当然,std::thread只运行一些代码,不会返回结果。但是,在C++11线程库中,您可以使用许多东西来返回结果,而不必使用std::ref和引用参数。

在解决这个问题之前,让我们先看看adder函数本身。我将对它进行一系列的改进。首先,您应该尝试使用正确的类型对std::vector进行索引:

代码语言:javascript
复制
using size_type = std::vector<int>::size_type;

int adder( const std::vector<int> & v, size_type begin, size_type end)
{
    for( ; begin < end; ++begin )
    {
        result = result + v.at( begin );
    }
}

这是可以的,但它可能更通用:如果值没有存储在std::vector中怎么办?相反,模板这样它就可以使用任何支持迭代器概念的东西:

代码语言:javascript
复制
template <typename Iterator>
int adder(Iterator begin, Iterator end)
{
    int result = 0;
    for(auto it = begin; it != end; ++it) {
        result += *it;
    }
    return result;
}

好的,到了那里,但是我们仍然可以改进这一点:如果我们想要对任何类型的数字进行求和,怎么办?(注意,这需要一个#include <iterator>):

代码语言:javascript
复制
template <typename Iterator>
std::iterator_traits<Iterator>::value_type 
adder(Iterator begin, Iterator end)
{
    std::iterator_traits<Iterator>::value_type result;
    for(auto it = begin; it != end; ++it) {
        result += *it;
    }
    return result;
}

好的,所以我们不再被锁在vectorint类型中了。但是,这种总结一组值的模式是非常普遍的,并且有一些库功能为我们处理:std::accumulate (注意,这需要一个#include <algorithm>):

代码语言:javascript
复制
template <typename Iterator>
typename std::iterator_traits<Iterator>::value_type
adder(Iterator begin, Iterator end)
{
    using T = typename std::iterator_traits<Iterator>::value_type;
    return std::accumulate(begin, end, T());
}

现在是线程部分。

C++11线程库有一个非常方便的函数,名为std::async。这允许您在线程中运行某些代码,并从中检索结果。它将返回已知的std::future (请注意,这需要一个#include <future>):

代码语言:javascript
复制
template <typename Iterator>
typename std::iterator_traits<Iterator>::value_type
parallel_sum(Iterator begin, Iterator end)
{
    using T = typename std::iterator_traits<Iterator>::value_type;
    auto midpoint = begin + std::distance(begin, end) / 2;
    std::future<T> f1 = std::async(std::launch::async, adder<Iterator>, begin, midpoint);
    std::future<T> f2 = std::async(std::launch::async, adder<Iterator>, midpoint, end);
    return f1.get() + f2.get();
}

然后,我们将如下所示:

代码语言:javascript
复制
int main()
{
    std::vector<int> v;
    for(int i = 0; i < 100000; ++i) {
        v.push_back(i);
    }
    int total = parallel_sum(v.begin(), v.end());
    std::cout << total << "\n";
}

这里可能一次就有太多的东西要吸收,但我将详细分析以下要点:

  • 尝试使您的功能与标准库提供的设施一起工作。迭代器渗透到容器/算法方面--如果可以的话,尝试使用迭代器而不是直接使用容器。
  • 在标准库中寻找可以帮助您执行常见任务(如std::accumulate )的功能。
  • 对于线程,如果您想要返回结果,请使用std::async而不是通过引用传递参数来存储结果。
票数 22
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/45557

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档