【问题标题】:Is it concurrency-safe to call concurrency::concurrent_vector::push_back while iterating over that concurrent_vector in other thread?在其他线程中迭代该 concurrent_vector 时调用 concurrency::concurrent_vector::push_back 是否并发安全?
【发布时间】:2019-11-15 12:37:18
【问题描述】:

push_backbeginendhttps://docs.microsoft.com/en-us/cpp/parallel/concrt/reference/concurrent-vector-class?view=vs-2019#push_back

但是下面的代码是断言。可能是因为元素已添加但尚未初始化。

struct MyData
   {
   explicit MyData()
      {
      memset(arr, 0xA5, sizeof arr);
      }
   std::uint8_t arr[1024];
   };

struct MyVec
   {
   concurrency::concurrent_vector<MyData> v;
   };

auto vector_pushback(MyVec &vec) -> void
   {
   vec.v.push_back(MyData{});
   }

auto vector_loop(MyVec &vec) -> void
   {
   MyData myData;
   for (auto it = vec.v.begin(); it != vec.v.end(); ++it)
      {
      auto res = memcmp(&(it->arr), &(myData.arr), sizeof myData.arr);
      assert(res == 0);
      }
   }

int main()
{
   auto vec = MyVec{};
   auto th_vec = std::vector<std::thread>{};
   for (int i = 0; i < 1000; ++i)
      {
      th_vec.emplace_back(vector_pushback, std::ref(vec));
      th_vec.emplace_back(vector_loop, std::ref(vec));
      }

   for(auto &th : th_vec)
      th.join();

    return 0;
}

【问题讨论】:

    标签: c++ concurrency concurrent-vector


    【解决方案1】:

    根据docs,在迭代concurrency::concurrent_vector 时附加到concurrency::concurrent_vector 应该是安全的,因为这些元素实际上并没有像std::vector 那样连续存储在内存中:

    concurrent_vector 对象在您追加或调整其大小时不会重新定位其元素。这使得现有的指针和迭代器在并发操作期间保持有效。

    但是,查看push_back 在 VS2017 中的实际实现,我看到以下内容,我认为这不是线程安全的:

    iterator push_back( _Ty &&_Item )
    {
        size_type _K;
        void *_Ptr = _Internal_push_back(sizeof(_Ty), _K);
        new (_Ptr) _Ty( std::move(_Item));
        return iterator(*this, _K, _Ptr);
    }
    

    我必须在这里推测_Internal_push_back,但我敢打赌它会分配原始内存来存储项目(并将最后一个元素指向这个新节点),以便下一行可以使用新位置。我想_Internal_push_back 是内部线程安全的,但是我没有看到在新位置之前发生任何同步。意味着以下是可能的:

    • 内存已获得且节点“存在”(尚未发生新位置)
    • 循环线程遇到此节点并执行memcmp 以发现它们不相等
    • 新进位发生。

    这里肯定存在竞争条件。我可以自发地重现问题,而且我使用的线程越多。

    我建议您在此问题上向 Microsoft 支持开一张票。

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    相关资源
    最近更新 更多