Подтвердить что ты не робот

Существуют ли в С++ 11 параллельные контейнеры?

В частности, я ищу очередь блокировки. Есть ли такая вещь в С++ 11? Если нет, то каковы мои другие варианты? Я действительно не хочу больше идти на уровень нити. Путь слишком подвержен ошибкам.

4b9b3361

Ответ 1

По словам Диего Дагума из Microsoft Visual С++ Team:

Повторяющийся вопрос (ну, один из многих) касается контейнеров STL и являются ли они безопасными потоками.

Взяв здесь слова Стефанов, реальность такова, что они arent, а не как ошибка, но как функция: наличие каждой функции-члена каждого STL контейнер, приобретающий внутренний замок, аннулирует производительность. В виде библиотека общего назначения, очень многократно используемая, на самом деле обеспечить правильность: правильный уровень размещения замков определяется тем, что делает программа. В этом смысле индивидуальные функции-члены не имеют такого правильного уровня.

Библиотека параллельных шаблонов (PPL) включает несколько контейнеров, которые обеспечивают поточный доступ к их элементам:

  • concurrent_vector Class - это контейнерный класс последовательности, который позволяет произвольный доступ к любому элементу. Он позволяет использовать concurrency -серверный доступ, доступ к элементу, доступ к итератору и операции обхода итератора.
  • concurrent_queue Class - это класс контейнера последовательностей, который позволяет получить доступ к своим элементам с первого раза, первым выходом. Он позволяет использовать ограниченный набор concurrency -секретных операций, таких как push и try_pop, чтобы назвать несколько.

Некоторые примеры здесь.

Также интересно: http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html.

Ответ 2

С++ 11 сам по себе не обеспечивает одновременные контейнеры. Однако есть варианты библиотеки. Помимо уже упомянутого PPL, не забудьте библиотеку Intel TBB.

Он имеет параллельные реализации queue, hash_map, set и vector. Но это не только поточно-безопасная библиотека контейнеров, но и параллельная версия стандартных алгоритмов (for-loop, reduce, sort,...).

Веб-сайт Intel TBB

Ответ 3

Я удивлен, что никто не упоминал moodycamel:: ConcurrentQueue. Мы используем его довольно долгое время, и он работает очень хорошо. Специфично, что его реализация блокируется, что сразу же приносит огромную скорость. Другие причины его использования (цитирование с официального сайта):

Существует не так много полноценных незакрепленных очередей для С++. Увеличение имеет один, но ограничивается объектами с тривиальными операторами присваивания и тривиальные деструкторы, например. Очередь Intel TBB не является без блокировки и требует тривиальных конструкторов. Там много академические документы, которые реализуют блокированные очереди на С++, но пригодные для использования исходный код трудно найти и еще более проверяет.

Некоторые тесты и сравнения доступны здесь, здесь и здесь.

Ответ 4

Интерфейсы контейнеров просто не были разработаны с этой целью. Для интерфейсов, которые они используют, блокировка, видимая клиенту, действительно является единственным способом добиться этого, гарантируя правильность и предсказуемое поведение. Это также было бы ужасно неэффективно, потому что количество приобретений было бы очень высоким (относительно хорошей реализации).

Решение 1

Перейдите по значению (если применимо).

Решение 2

Создайте коллекцию простых реализаций на болтах, которые вы можете использовать для передачи контейнеров, удерживая блокировку области видимости (считайте ее псевдо С++):

template <typename TCollection>
class t_locked_collection {
public:
    t_locked_collection(TCollection& inCollection, t_lock& lock) : collection(inCollection), d_lock(lock), d_nocopy() {
    }

    TCollection& collection;
    // your convenience stuff
private:
    t_scope_lock d_lock;
    t_nocopy d_nocopy;
};

тогда вызывающий соединяет блокировку с коллекцией, а затем вы обновляете свои интерфейсы, чтобы использовать (пропустить) тип контейнера, где это необходимо. Это просто расширение класса бедных.

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

Другой вариант:

template <typename TCollection>
class t_lockable_collection {
public:
// ...
private:
    TCollection d_collection;
    t_mutex d_mutex;
};

// example:
typedef t_lockable_collection<std::vector<int> > t_lockable_int_vector;

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