Diğer iş parçacığında aynı eşzamanlı_vektör üzerinden yineleme yaparken eşzamanlılık :: concurrent_vector :: push_back öğesini çağırmak eşzamanlı olarak güvenli midir?


9

push_back , başlar , sonu eşzamanlı kasa olarak tarif edilmektedir https://docs.microsoft.com/en-us/cpp/parallel/concrt/reference/concurrent-vector-class?view=vs-2019#push_back

Ancak, aşağıdaki kod öne sürülüyor. Muhtemelen eleman eklendiğinden, ancak henüz başlatılmadığından.

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

Yanıtlar:


2

Dokümanlara göre , concurrency::concurrent_vectorüzerinde yinelenen bir süre eklemek güvenli olmalıdır, çünkü elemanlar aslında aşağıdaki gibi bellekte bitişik olarak saklanmaz std::vector:

Bir concurrent_vectornesne, eklediğinizde veya yeniden boyutlandırdığınızda öğelerinin yerini değiştirmez. Bu, mevcut işaretçilerin ve yineleyicilerin eşzamanlı işlemler sırasında geçerli kalmasını sağlar.

Ancak, push_backVS2017 gerçek uygulama bakarak , iş parçacığı güvenli olduğunu düşünmüyorum, aşağıdakileri görüyorum:

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_backBurada spekülasyon yapmalıyım, ancak öğeyi saklamak için ham bellek tahsis ettiğinden ve bir sonraki satırın yeni yerleştirmeyi kullanabilmesi için bu yeni düğüme doğru işaret ettiğini iddia ediyorum. Bunun _Internal_push_backdahili olarak iş parçacığı açısından güvenli olduğunu hayal edebiliyorum , ancak yeni yerleştirmeden önce herhangi bir senkronizasyon gerçekleşmiyor. Yani aşağıdakiler mümkündür:

  • bellek elde edildi ve düğüm "mevcut" (henüz yeni yerleşim gerçekleşmedi)
  • Döngü iş parçacığı bu düğümle karşılaşır ve memcmpeşit olmadıklarını keşfetmeye çalışır
  • yerleşim yeni olur.

Burada kesinlikle bir yarış durumu var. Sorunu kendiliğinden çoğaltabilirim, daha fazla iş parçacığı daha.

Bu konuda Microsoft desteği olan bir bilet açmanızı öneririz.



1
MSFT güncellenmiş belgeleri github.com/MicrosoftDocs/cpp-docs/commit/…
pidgun
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.