【问题标题】:How to process std containers with threads?如何用线程处理标准容器?
【发布时间】:2016-11-11 00:17:41
【问题描述】:

我有一个名为my_objects 的集合(目前是std::list<MyClass*>,但也可以是std::map<int, MyClass*>),其中包含指向MyClass 实例的指针。

目前,我这样处理数组:

for(std::list<MyClass*>::iterator iterator = my_objects.begin(), end = my_objects.end(); iterator != end; ++iterator) {

    (*iterator)->someFunction();
    // ...

}

someFunction 可能会改变当前元素的一些属性,并可能读取其他元素的一些属性。但是没有属性被另一个实例更改并读取。所以无论迭代顺序如何,结果都是一样的。

我想重写这个循环,使用四个std::thread,并用第一个线程处理第一季度的元素,用线程处理第二季度的元素,等等......

是否可以跳转到集合内部并在那里开始迭代?这是处理这样一个集合的推荐方法吗?如果没有,应该怎么做?

【问题讨论】:

  • 你的问题不是线程问题,而是随机访问std::liststd::list不支持随机访问,请使用std::vector

标签: c++ multithreading c++11 collections std


【解决方案1】:

首先,现代 C++ 代码使用范围迭代:

for (const auto &ptr:my_objects)
{
    ptr->someFunction();
}

更简洁,更少输入,避免常见的迭代陷阱。

现在,就std::list 的分区而言,没有std::list 方法会在列表中间某处返回初始迭代器。对于std::vector 的随机访问迭代器,这是微不足道的,但这不是std::list 的用途。所以,如果你想把你的容器改成std::vector,这就很容易了。

不过,遍历整个列表并不难,只处理每个nth 元素:

size_t p=0;

for (const auto &ptr:my_objects)
{
    if (p == 0)
        ptr->someFunction();
    p = (p+1) % 4;
}

所以现在,该线程为列表中的每四个元素以及列表中所有元素的四分之一调用someFunction()

所以,这里只需要四个线程在这里迭代,唯一的区别是第一个线程的初始值p设置为0,如图所示;第二个线程的初始值p设置为1;当然,第三个和第四个线程的初始值p设置为2和3。

这会将列表整齐地分成四个相等的部分,并将列表元素分配给四个线程之一进行处理。

【讨论】:

    【解决方案2】:

    推荐的方法是使用原子计数器来获取每个线程处理的唯一对象。每个线程的线程函数看起来类似于这样(伪代码):

    std::atomic<int> atomic_ctr(0);
    
    void threadfunc() {
      list_iterator iter = list.begin();
      int current_list_pos=0;
      int next_pos;
      while((next_pos = atomic_ctr++) < list.size()) {
        while (current_list_pos < next_pos) {
          ++iter;
          ++current_list_pos;
        }
        iter->func();
      }
    }
    

    【讨论】:

      【解决方案3】:

      在最简单的情况下,您可以创建一个工作对象(将在线程内调用),这样您就可以使用对容器的引用以及它应该更改的范围(元素索引或迭代器)来构造它。

      如果您的工作人员更改的数据部分确实不存在依赖关系,那么这个应该工作,即使它是一个 hack。

      否则,您将不得不在您的容器周围创建一种包装器对象,该对象实现了用于读取和写入特定元素的锁定机制(我建议使用 boost::upgrade_lock)。

      然后,您的线程工作对象将需要与此(共享)对象通信,以获取对您的容器的读写访问权限。

      【讨论】:

      • 这个问题不是关于锁定的。
      • 有关线程访问共享数据的问题通常与访问锁定有关。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-10
      • 1970-01-01
      • 2020-01-21
      • 2018-06-13
      • 2013-05-25
      相关资源
      最近更新 更多