boost::uuids::random_generator и уникальность с несколькими потоками

Когда я генерирую случайное число с одним потоком, дубликат в 4M uuids не генерируется, но если я генерирую с двумя потоками каждый 1M, я вижу примерно 16-20 дубликатов. Что может быть причиной?

class TestUuid 
{
 public:
  std::string GenerateUUid(){
       boost::uuids::uuid uid;
       {
          boost::mutex::scoped_lock(m_mRandomGen);
          uid = m_oRandomGen();
       }
       std::stringstream ss;
       ss << uid;
       return ss.str();
  }


  void TestUid(std::map<std::string, unsigned>& mUids, unsigned count){  
    for(unsigned i = 0; i < count; ++i) {
        std::string sUid = GenerateUUid();
        std::map<std::string, unsigned>::const_iterator it = mUids.find(sUid);           
        if(it == mUids.end()){
           mUids[sUid] = i;
        }else {
         std::cerr << "Duplicate uid:" << sUid << " found in  thread id:" << pthread_self() << ", counter:" << i << ", earlier counter:" << it->second << ", id:" << it->first<< std::endl;
        }
    } 
  }

   TestUnique() {
     unsigned count = 4000000;
     std::map<std::string, unsigned> uuids;
     TestUid(uuids, count);
   }

   TestUniqueMultiThread() {
    unsigned count = 1000000;
    std::map<std::string, unsigned> mUids1;
    boost::thread t1(boost::bind(&TestUuid::TestUid, this, mUids1, count));

    std::map<std::string, > Uunsignedids2;
    boost::thread t2(boost::bind(&TestUuid::TestUid, this,  mUids2, count));
    t1.join();
    t2.join();
   }

 private:
   boost::mutex m_mRandonGen;
   boost::uuids::random_generator m_oRandomGen;

}

int main() {
 TestUid oTest;
 oTest.TestUnique();  //work fine. no duplicate in 4M uuids
 oTest.TestUniqueMultiThread(); // around 16-20 duplicates in total 2*1M = 2M uuids
 return EXIT_SUCCESS;
}

ниже журнал.

Идентификатор дубликата: 9f4bfa5c-8e41-4012-ba3e-0b3e631834dc, найденный в идентификаторе нити: 1103669568, счетчик: 12016, предыдущий счетчик: 12015, идентификатор: 9f4bfa5c-8e41-4012-ba3e-0b3e631834dc
Идентификатор дубликата: 0237b010-cb8f-4b89-9f47-042722902883 найден в идентификаторе нити: 1103669568, счетчик: 65778, более ранний счетчик: 65777, идентификатор: 0237b010-cb8f-4b89-9f47-042722902883
Идентификатор дубликата: 7a999ce7-0936-4642-b796-485334fc6ba4 найден в идентификаторе нити: 1093179712, счетчик: 170570, более ранний счетчик: 170568, идентификатор: 7a999ce7-0936-4642-b796-485334fc6ba4
Идентификатор дубликата: 09e1028b-5fc9-4fcd-ab70-991c02d47aec найден в идентификаторе потока: 1093179712, счетчик: 208740, более ранний счетчик: 208739, идентификатор: 09e1028b-5fc9-4fcd-ab70-991c02d47aec
Идентификатор дубликата: 66eb72f5-a3de-4941-8a64-6dad773f0ffb найден в идентификаторе потока: 1093179712, счетчик: 211449, более ранний счетчик: 211448, идентификатор: 66eb72f5-a3de-4941-8a64-6dad773f0ffb
Идентификатор дубликата: 8bccb459-1e70-4920-8486-6b0c5dcb3992 найден в идентификаторе потока: 1093179712, счетчик: 212972, предыдущий счетчик: 212971, идентификатор: 8bccb459-1e70-4920-8486-6b0c5dcb3992
Идентификатор дубликата: bb8109e3-6529-4122-a015-a9746900f692 найден в идентификаторе нити: 1093179712, счетчик: 239296, предыдущий счетчик: 239295, идентификатор: bb8109e3-6529-4122-a015-a9746900f692
Идентификатор дубликата: a02ea282-b49b-4e4f-98a3-01406824c888 найден в идентификаторе нити: 1103669568, счетчик: 338582, предыдущий счетчик: 338581, идентификатор: a02ea282-b49b-4e4f-98a3-01406824c888
Идентификатор дубликата: 8bc848d7-bbe9-405c-9ef3-4d5ec312aa5e, найденный в идентификаторе потока: 1093179712, счетчик: 472035, предыдущий счетчик: 472010, идентификатор: 8bc848d7-bbe9-405c-9ef3-4d5ec312aa5e
Идентификатор дубликата: d3d8e09f-c410-4ce0-9a75-2a0c363db89c найден в идентификаторе нити: 1093179712, счетчик: 531441, предыдущий счетчик: 531440, идентификатор: d3d8e09f-c410-4ce0-9a75-2a0c363db89c
Идентификатор дубликата: 3130184f-345e-4d1c-bb01-d481eec29704, найденный в идентификаторе нити: 1093179712, счетчик: 548770, предыдущий счетчик: 548769, идентификатор: 3130184f-345e-4d1c-bb01-d481eec29704
Идентификатор дубликата: 29572641-2487-400a-926f-9bbf7ca176b4, найденный в идентификаторе потока: 1093179712, счетчик: 710813, предыдущий счетчик: 710811, идентификатор: 29572641-2487-400a-926f-9bbf7ca176b4
Идентификатор дубликата: 36b3567d-5f06-4c72-a395-e6f6ce056c6b найден в идентификаторе нити: 1093179712, счетчик: 728598, предыдущий счетчик: 728597, идентификатор: 36b3567d-5f06-4c72-a395-e6f6ce056c6b
Идентификатор дубликата: 3290cb7e-2535-43bc-b53c-71ac0bc4fca1, найденный в идентификаторе нити: 1103669568, счетчик: 846883, предыдущий счетчик: 846881, идентификатор: 3290cb7e-2535-43bc-b53c-71ac0bc4fca1
Идентификатор дубликата: 59137657-2b2a-473e-b12c-1890d6058ca2, найденный в идентификаторе нити: 1093179712, счетчик: 814812, предыдущий счетчик: 814810, идентификатор: 59137657-2b2a-473e-b12c-1890d6058ca2

1 ответ

Решение

Это распространенная ошибка при использовании блокировок RAII: вы забыли дать своей блокировке имя в строке

      boost::mutex::scoped_lock(m_mRandomGen);

так что это ничего не блокировало вообще. Измените это на

      boost::mutex::scoped_lock lk(m_mRandonGen); // note the typo in mutex name

РЕДАКТИРОВАТЬ: что на самом деле произошло: не было ошибки компилятора, несмотря на опечатку в имени мьютекса, потому что объявление

type(name);

такой же как

type name;

если имя не было объявлено ранее. Другими словами, вы по умолчанию создали новый scoped_lock называется m_mRandomGen, не связанный с мьютексом.

Другие вопросы по тегам