#c #templates #mutex
#c #шаблоны #мьютекс
Вопрос:
Можете ли вы придумать элегантный способ создания (членских) функций с дополнительным блоком мьютексов? Давайте проигнорируем макросы по понятным причинам.
Конечно, самый простой способ сделать это — использовать две функции:
int getIndex() const { std::lock_guard m( mtx ); return nm_getIndex(); }
int nm_getIndex() const { return _index; }
Это создает эффективный код, но он основан на дублировании кода. В принципе, в итоге вы получите большинство объявлений функций дважды.
Другим способом было бы превратить их в функции шаблона. Логический аргумент шаблона будет функционировать как «en- / disabler». Затем вы могли бы вызвать функцию следующим образом:
auto index = getIndex< NoMutex >();
всякий раз, когда функция используется внутри (и блокирует мьютекс в противном случае). Проблема здесь в том, чтобы убедиться, что мьютекс разблокирован, даже когда генерируется исключение. То есть вы не можете просто использовать что-то вроде
if constexpr( MutexOn == true ) {
mutex.lock();
}
do some stuff;
if constexpr( MutexOn == true ) {
mutex.unlock();
}
Единственное, о чем я могу сейчас думать, это создать класс вокруг мьютекса и поместить его в объединение. Тогда класс может либо «воспроизвести lock_guard», либо ничего не делать. Хотя я почти уверен, что это будет правильно оптимизировано в коде выпуска, он по-прежнему выглядит громоздким и негибким.
Поэтому мне интересно, можете ли вы придумать что-нибудь получше?
Спасибо!
Комментарии:
1. Конечно, существует очевидный метод специализации шаблонов, но это приводит к нескольким методам для 1 действия, как вы сами сказали.
2. Подход «уникальный ptr для защиты блокировки» примерно такой же, как и в объединенной версии, но он добавляет выделение памяти.
Ответ №1:
Самый простой подход, который я могу придумать, это:
-
Создайте класс noop lock_guard.
-
Создайте шаблонную функцию, которая всегда использует блокировку типа, указанного в качестве параметра шаблона.
-
Если вам нужна неблокирующая версия функции, которую вы можете передать в noop guard
Например:
template<typename Guard>
int getIndex<Guard>() const { Guard m( lock ); return nm_getIndex(); }
class NoopLockGuard ; //dummy class. it does absolutely nothing
int i = getIndex<NoopLockGuard>()
int j = getIndex<std::lock_guard>()
Компилятор должен иметь возможность оптимизировать версию NoopLockGuard
таким образом, чтобы она приводила к минимальному или нулевому снижению производительности.
Комментарии:
1. Спасибо, это действительно выглядит красиво. Вы даже можете передавать другие блокировки, такие как блокировки с ограниченным доступом и т. Д. 🙂