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

Threadsafe Векторный класс для С++

Кто-нибудь знает быстрый и грязный потоковый векторный класс для С++? Я многопользовательский код, и я считаю, что проблема, которую я имею, связана с тем, как используются векторы. Я планирую переписать код, но, прежде чем я схожу с ума, переделаю код, я бы хотел проверить его с помощью вектора потокобезопасности. Я также думаю, что если бы такая вещь была там, это было бы намного проще, чем написать мою собственную версию.

4b9b3361

Ответ 1

Это сложно из-за алгоритмов.

Предположим, вы завернули вектор таким образом, чтобы все его функции-члены были сериализованы с использованием мьютекса, например, Java-синхронизированных методов. Тогда одновременные вызовы std::remove на этом векторе все равно не будут безопасными, потому что они полагаются на просмотр вектора и изменение его на основе того, что они видят.

Таким образом, ваш LockingVector должен будет специализировать каждый шаблон в стандартных алгоритмах, чтобы блокировать все это. Но тогда другие алгоритмы, такие как std::remove_if, будут вызывать пользовательский код под замком. Выполнение этого молча за кулисами - это рецепт блокировки инверсии, как только кто-то начинает создавать векторы объектов, которые сами внутренне берут блокировки вокруг всех своих методов.

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

template <typename T>
class LockedVector {
    private:
    SomeKindOfLock lock;
    std::vector<T> vec;
};

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

Ответ 2

Вы можете проверить TBB (например concurrent_vector). Я никогда не использовал его, хотя, честно говоря, я считаю, что объекты защиты объектов вокруг объекта легче (особенно если вектор правильно инкапсулирован).

Ответ 3

Я думаю, вам будет гораздо легче продолжать использовать std::vector, но для защиты параллельного доступа с использованием какого-либо мьютекса или другого объекта синхронизации операционной системы. Вы также обязательно захотите использовать RAII, если вы используете мьютекс.

Ответ 4

Как говорит Скотт Мейерс в эффективной книге STL, в контейнере с потоком, вы можете ожидать, что:

  • Несколько считываний безопасны
  • Несколько записей в разных контейнерах безопасны.

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

Ответ 5

Я забыл, кто это обсудил, но одна стратегия для создания контейнера с потоками выглядит следующим образом:

  • Все общедоступные методы класса должны блокировать вектор и должны возвращать логическое значение, если они были успешными (и они могут не удаться!). Поэтому вместо f = myvec[i] используйте if (myvec.tryGet(i, &f)) {...} и соответствующим образом реализуйте класс.
  • Не указывайте метод подсчета. Пользователи должны использовать итераторы для перемещения по вектору.

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

Хромой и простой способ обеспечить "потокобезопасный" вектор - просто взять стандартный вектор и заблокировать вектор для каждого метода. Но если вы это сделаете, вы все равно можете сломать код (например, цикл, который выполняет итерацию от 0 до vec.count, может иметь изменение счетчика во время итерации).

Второе средство предоставления "поточно-безопасных" контейнеров - это создание неизменяемых контейнеров (каждый метод возвращает новый контейнер. Это определенно обсуждаемый Эриком Липпертом Это С#, но легко переводит на код С++, в основном. Вам все равно нужно заблокировать контейнер, когда вы его используете, но все страшные проблемы, связанные с переполнением буфера, когда итераторы ломаются и что не исчезают. контейнер, вероятно, относительно второй характер для тех, кто испытывает функциональное программирование.

Ответ 6

Если вы еще этого не сделали, рассмотрите возможность использования concurrent_vector из библиотеки tbb. С++ STL-векторы не являются потокобезопасными, поэтому, если вы планируете модифицировать векторный ресурс из нескольких потоков, самым простым решением, которое я нашел, является использование concurrent_vector.