他のスレッドでそのconcurrent_vectorを反復しながら、concurrency :: concurrent_vector :: push_backを呼び出すことは、同時実行安全ですか?


9

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;
}

回答:


2

docsによると、concurrency::concurrent_vector要素は実際には次のようにメモリに隣接して格納されていないため、繰り返し処理しながらしばらく追加しても安全ですstd::vector

concurrent_vectorオブジェクトは、あなたがそれに追加するとき、その要素を再配置やサイズを変更しません。これにより、既存のポインターとイテレーターが並行操作中に有効なままになります。

ただし、push_backVS2017の実際の実装を見ると、次のことがわかります。これはスレッドセーフではないと思います。

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サポートでチケットを開くことをお勧めします。


1
報告
pidgun

1
MSFT更新されたドキュメント github.com/MicrosoftDocs/cpp-docs/commit/...
pidgun
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.