C ++ Thread-Safe Map - PullRequest
       44

C ++ Thread-Safe Map

14 голосов
/ 04 мая 2009

Кто-нибудь знает, где я могу найти имплиментацию, которая обернет std::map и сделает его безопасным для потоков? Когда я говорю «потокобезопасный», я имею в виду, что он предлагает только последовательный доступ к карте, по одному потоку за раз. Оптимально, эта карта должна использовать только стандартные библиотеки и / или конструкции boost.

Ответы [ 8 ]

11 голосов
/ 04 мая 2009

Не соответствует указанным вами критериям, но вы можете взглянуть на контейнеры TBB . Существует так называемый concurrent_hash_map, который позволяет нескольким потокам одновременно получать доступ к данным на карте. Есть некоторые детали, но все хорошо документировано и может дать вам представление о «параллельном контейнере». В зависимости от ваших потребностей это может быть совершенно неуместно ...

4 голосов
/ 04 мая 2009

Как правило, классам коллекций не рекомендуется обеспечивать безопасность потоков, поскольку они не могут знать, как они используются. Вы будете гораздо лучше обслуживаться, если будете реализовывать свои собственные механизмы блокировки в конструкциях более высокого уровня, которые используют коллекции.

2 голосов
/ 04 мая 2009

Повышение shared_mutex обеспечит лучший подход для нескольких читателей / писателей к переносу стандартной карты с учетом ваших ограничений. Я не знаю каких-либо «готовых» реализаций, которые объединяют эти два, так как задача, как правило, тривиальная.

1 голос
/ 10 сентября 2010

Вы можете посмотреть Thread Safe Library Library

1 голос
/ 04 мая 2009

Попробуйте эту библиотеку

http://www.codeproject.com/KB/threads/lwsync.aspx

Он реализован в современном подходе, основанном на политике С ++.

Вот некоторая вырезка из ссылки, чтобы показать идею с «векторным» случаем

typedef lwsync::critical_resource<std::vector<int> > sync_vector_t;
sync_vector_t vec;

// some thread:
{
   // Critical resource can be naturally used with STL containers.
   sync_vector_t::const_accessor vec_access = vec.const_access();
   for(std::vector<int>::const_iterator where = vec_access->begin();
         where != vec_access->end();
         ++where;
        )
   std::cout << *where << std::endl;
}

sync_vector_t::accessor some_vector_action()
{
   sync_vector_t::accessor vec_access = vec.access();
   vec_access->push_back(10);
   return vec_access;
   // Access is escalated from within a some_vector_action() scope
   // So that one can make some other action with vector before it becomes
   // unlocked.
}

{
   sync_vector_t::accessor vec_access = some_vector_action();
   vec_access->push_back(20);
   // Elements 10 and 20 will be placed in vector sequentially.
   // Any other action with vector cannot be processed between those two
   // push_back's.
}
1 голос
/ 04 мая 2009

Это зависит от приложения для реализации. «Потоково-безопасная» карта будет делать отдельные вызовы в поточно-ориентированной карте, но многие операции должны быть выполнены поточно-безопасными для вызовов. Приложение, использующее карту, должно связать мьютекс с картой и использовать этот мьютекс для координации доступа к ней.

Попытка сделать потокобезопасные контейнеры была ошибкой в ​​Java, и это было бы ошибкой в ​​C ++.

0 голосов
/ 20 июня 2018

Здесь есть предложение (мной - бесстыдный плагин), которое оборачивает объекты (включая STL контейнеры) для эффективного (нулевого) потока безопасного доступа:

https://github.com/isocpp/CppCoreGuidelines/issues/924

Основная идея очень проста. Существует всего несколько классов-оболочек, используемых для принудительной блокировки чтения / записи и, в то же время, представления const (для чтения) и неконстантного (для чтения и записи) обернутого объекта.

Идея состоит в том, чтобы сделать невозможным неправильный доступ во время компиляции к ресурсу, совместно используемому потоками.

Код реализации можно найти здесь:

https://github.com/galik/GSL/blob/lockable-objects/include/gsl/gsl_lockable

0 голосов
/ 26 января 2018

Я придумал это (что, я уверен, может быть улучшено, если принять более двух аргументов):

template<class T1, class T2>
class combine : public T1, public T2
{
public:

    /// We always need a virtual destructor.
    virtual ~combine() { }
};

Это позволяет вам:

// Combine an std::mutex and std::map<std::string, std::string> into
// a single instance.
combine<std::mutex, std::map<std::string, std::string>> lockableMap;

// Lock the map within scope to modify the map in a thread-safe way.
{
    // Lock the map.
    std::lock_guard<std::mutex> locked(lockableMap);

    // Modify the map.
    lockableMap["Person 1"] = "Jack";
    lockableMap["Person 2"] = "Jill";
}

Если вы хотите использовать std :: recursive_mutex и std :: set, это также сработает.

...