Я знаю, что это возможно, используя boost::UpgradeLockable
в C ++ 14.
Есть ли что-нибудь подобное для C ++ 11?
Обновляемая блокировка может быть написана поверх простых примитивов блокировки.
struct upgradeable_timed_mutex {
void lock() {
upgradable_lock();
upgrade_lock();
}
void unlock() {
upgrade_unlock();
upgradable_unlock();
}
void shared_lock() { shared.shared_lock(); }
void shared_unlock() { shared.shared_unlock(); }
void upgradable_lock() { unshared.lock(); }
void ungradable_unlock() { unshared.unlock(); }
void upgrade_lock() { shared.lock(); }
void upgrade_unlock() { shared.unlock(); }
private:
friend struct upgradable_lock;
std::shared_timed_mutex shared;
std::timed_mutex unshared;
};
и аналогичные для временных и пробных вариантов. Обратите внимание, что синхронизированные варианты, которые получают доступ к двум мьютексам подряд, должны выполнять дополнительную работу, чтобы не тратить в два раза больше запрашиваемого времени, и try_lock
должен быть осторожен с состоянием первой блокировки на случай, если 2-й сбой.
Тогда вы должны написать upgradable_lock
со способностью порождать std::unique_lock
по требованию.
Естественно, это рукописный код безопасности потока, поэтому он вряд ли будет правильным.
В C ++ 1z вы также можете написать несвязанную версию (с std::shared_mutex
а также std::mutex
).
Менее конкретно, может быть ровно одна обновляемая блокировка или блокировка записи одновременно. Это то, что unshared
мьютекс представляет.
Пока вы держите unshared
никто не пишет в защищенные данные, поэтому вы можете читать из них, не удерживая общий мьютекс.
Если вы хотите обновить, вы можете получить уникальную блокировку на общем мьютексе. Это не может сделать взаимоблокировку, пока никакие читатели не пытаются перейти на обновление. Это исключает читателей из чтения, вы можете писать, а затем вы отпускаете его и возвращаетесь обратно в состояние только для чтения (где вы держите только неразделенный мьютекс).
Других решений пока нет …