ปลอดภัยหรือไม่ที่จะเรียกใช้พร้อมกัน :: concurrent_vector :: push_back ขณะที่วนซ้ำ concurrent_vector นั้นในเธรดอื่น?


9

push_back , เริ่มต้น , ปลายจะมีการอธิบายเป็นที่ปลอดภัยพร้อมกันใน https://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

ตามเอกสารมันควรจะปลอดภัยที่จะผนวก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 ในอันนี้



1
MSFT เอกสารที่อัปเดตแล้ว github.com/MicrosoftDocs/cpp-docs/commit/…
pidgun
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.