Кто-нибудь знает быстрый и грязный потоковый векторный класс для С++? Я многопользовательский код, и я считаю, что проблема, которую я имею, связана с тем, как используются векторы. Я планирую переписать код, но, прежде чем я схожу с ума, переделаю код, я бы хотел проверить его с помощью вектора потокобезопасности. Я также думаю, что если бы такая вещь была там, это было бы намного проще, чем написать мою собственную версию.
Threadsafe Векторный класс для С++
Ответ 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.