代码之家  ›  专栏  ›  技术社区  ›  Agnel Kurian

原子性std::vector::push_back()并返回索引

  •  5
  • Agnel Kurian  · 技术社区  · 14 年前

    我需要创建一个函数,它将一个值附加到一个向量上,并返回刚刚附加的值的索引。

    例子:

    int append(std::vector<int>& numbers, int number){
      int retval = numbers.size();
      // what if some other thread calls push_back(number) in between these calls?
      numbers.push_back(number);
      return retval;
    }
    

    我希望原子地这样做,以便返回的索引总是正确的,即使可能有多个线程向向量追加值。如果 push_back 返回刚添加的项的索引。如何保证返回正确的索引?

    5 回复  |  直到 14 年前
        1
  •  11
  •   Community CDub    7 年前

    std::vector 没有内置线程支持。你可以使用 boost::mutex 扩展它:

    int append(std::vector<int>& numbers, int number){
      boost::mutex::scoped_lock slock( my_lock );
      int retval = numbers.size();
      numbers.push_back(number);
      return retval;
    }
    

    您需要以这种方式保护任何读/写操作。另一种方法是为创建包装类 STD::载体 这将通过螺纹支撑来扩展它。检查 this 有关详细信息的问题。

        2
  •  3
  •   sharptooth    14 年前

    STL容器不是线程安全的(甚至调用 push_back() 单独使用),您必须自己解决这个问题-在STL之外使用一些合适的同步原语。

        3
  •  2
  •   Rick    14 年前

    在Visual Studio 2010中,可以使用 concurrent_vector 为此,它提供了同步增长功能。 This topic 列出每个并发容器。

    请注意,这些也可以在英特尔的tbb中使用相同的语法+语义,因此可以跨平台使用。

        4
  •  0
  •   Sergey Kurenkov    14 年前

    您需要使用互斥体来确保返回正确的索引

        5
  •  0
  •   Jon Hanna    14 年前

    最有力的保证方案是在所有这些操作上锁定整个向量(这意味着控制 每一个 从代码中的任何地方进行操作,这实际上意味着创建一个同步向量)。

    可能是这样简单的事情可以为您的目的:

    int append(std::vector<int>& numbers, int number){
      int retval = numbers.size();
      // what if some other thread calls push_back(number) in between these calls?
      numbers.push_back(number);
      int newSize = numbers.size();
      //this bit is as a short-cut in common, easy, cases
      if(newSize = retval + 1) //no need for further complication
        return retval;
      while(++retval < newSize)
        if(numbers[retval] == number)
          return retval;
      //If we get this far, numbers have been deleted, not added. More discussion below.
    }
    

    有一点是,如果线程推送3、3、3,那么返回的索引将是错误的,尽管它仍然是3的索引。这是否可以取决于你的目的。

    另一个问题是,如果在这段时间内向量被弹出或以其他方式缩短,那么我们至多只能在上面的代码中添加注释,更糟的是,它的错误(当我们获得新闻大小后,它们再次弹出,然后访问[retval]将变为无效)。您需要考虑这种情况是否会发生(也许您从其他代码中知道它永远不会发生),以及如果会发生这种情况该怎么做。

    如果这种限制对于您的用例来说太大了,那么生成完全同步的向量恐怕是我能想到的最好的方法。