Элегантный переключатель включения / выключения мьютекса для функций? - PullRequest
3 голосов
/ 15 апреля 2019

Можете ли вы подумать о элегантном способе создания (member-) функций с помощью дополнительного мьютекс-шкафчика?Давайте проигнорируем макросы по понятным причинам.

Конечно, самый простой способ сделать это, имея две функции:

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 Ответ

3 голосов
/ 15 апреля 2019

Самый простой подход, который я могу придумать:

  1. Создать класс noop lock_guard.

  2. Создать шаблонную функцию, которая всегда используетблокировка защиты типа, указанного в качестве параметра шаблона.

  3. Если вам нужна версия функции без блокировки, вы можете передать 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 таким образом, чтобы это повлекло за собой минимальное или нулевое снижение производительности.

...