Реализация Concurrent_hash_map, выбрасывающая SIGSEGV - PullRequest
0 голосов
/ 02 сентября 2018

Я пытаюсь использовать tbb concurrent_hash_map для увеличения производительности моего приложения. Прочитайте об этом и примените в соответствии с моим приложением, но я вижу сбои ..

Итак, мое приложение представляет собой многопоточное приложение, в котором я храню пары, ключ - char *, а значение - целое число. Псевдокод выглядит так:

В .h файле,

typedef tbb::concurrent_hash_map<const void*, unsigned, Hasher> tbb_concurrent_hash;
tbb_concurrent_hash concurrent_hash_table;
tbb_concurrent_hash::accessor  write_lock;
tbb_concurrent_hash::const_accessor read_lock;

В файле .c,

void  storeName(const char * name)   {
    int id=0;

    // This creates a pair object of name and index
    std::pair object(name, 0);

    // read_lock is a const accessor for reading. This find function searches for char* in the table and if not found, create a write_lock.

    bool found = concurrent_hash_table.find(read_lock, name);  
    if (found == FALSE) {
      concurrent_hash_table.insert(write_lock, name);
      // Get integer id somehow.
      id = somefunction();
      write_lock->second = id; 
      write_lock.release();         
    } else {
      // if the name is found in the table then get the value and release it later
      id = read_lock->second;
      read_lock.release();
    }
}

Насколько я понимаю, у меня все хорошо с реализацией, но, как я уже сказал, произойдет несколько сбоев, когда find возвращает мне FALSE. Аварии также имеют следы мьютексов.

1 Ответ

0 голосов
/ 02 сентября 2018

Ваши «блокировки», то есть методы доступа объявлены глобальными в файле .h. Итак, в основном вы пишете в общий экземпляр scoped_lock ..., который логически ведет к гонке данных. Средства доступа похожи на классы std :: shared_ptr и std :: scoped_lock в одном, или проще - указатель на ваш результат и защита блокировки данных, на которые он указывает. Вы не хотите использовать один глобальный указатель из нескольких потоков. Объявите их локально в области, к которой вы хотите иметь такой доступ (и вам не нужно было бы также вызывать .release())

Другая проблема - гонка данных между find () и insert (). Два или более потоков могут решить, что их нужно вставить, поскольку они ничего не нашли. В этом случае первый поток вставит новый элемент, в то время как другие потоки вернут существующий элемент, поскольку insert () действует как find (), если существует существующий элемент. Проблема в том, что ваш код этого не учитывает.

Я понимаю, почему вам может потребоваться перепроверить использование const_accessor, поскольку блокировка чтения более масштабируема. Но вместо этого вы можете захотеть использовать bool insert( const_accessor& result, const value_type& value ); с блокировкой чтения (const_accessor) и value_type вместо только ключа, что инициализирует всю пару в случае добавления нового элемента.

...