Я использовал следующий вид ожидания / сигнала, чтобы потоки информировали друг друга.
std::condition_variable condBiz;
std::mutex mutexBar;
..
void Foo::wait()
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
if (waitPoint.owns_lock())
{
condBiz.wait(waitPoint);
}
}
void Foo::signal()
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
condBiz.notify_all();
}
void Foo::safeSection(std::function<void(void)> & f)
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
f();
}
Затем преобразовал механизм блокировки / разблокировки из unique_lock в lock_guard, потому что я не возвращаю unique_lock для использования где-то еще (кроме wait / signal), и у lock_guard меньше издержек:
void Foo::safeSection(std::function<void(void)> & f)
{
std::lock_guard<std::mutex> waitPoint(mutexBar); // same mutex object
f();
}
и это работает.
Это работает для всех платформ или просто похоже на работу для текущей платформы? Могут ли unique_lock и lock_guard работать друг с другом, используя один и тот же объект мьютекса?
И то и другое std::unique_lock
а также std::lock_guard
заблокируйте связанный мьютекс в конструкторе и разблокируйте его в деструкторе.
std::unique_lock
:
Функции-члены
(конструктор) создает unique_lock, опционально блокируя предоставленный мьютекс
(деструктор) разблокирует связанный мьютекс, если он принадлежит
и то же самое для std::lock_guard
:
Функции-члены
(конструктор) создает lock_guard, опционально блокируя данный мьютекс
(деструктор) уничтожает объект lock_guard, разблокирует нижележащий мьютекс
Поскольку оба ведут себя одинаково, при использовании в качестве оболочки типа RAII, я не вижу препятствий для их совместного использования, даже с одним и тем же мьютексом.
В комментариях к вашему сообщению было указано, что проверка того, принадлежит ли unique_lock в Foo :: wait (), бессмысленна, потому что связанный мьютекс должен принадлежать блокировке в этой точке для продолжения потока.
Вместо этого ваша условная переменная должна проверять какое-либо значимое условие, и она должна делать это в цикле while или с помощью перегрузки condition_variable :: wait, который принимает предикат в качестве второго аргумента, который требуется для стандарта C ++, чтобы иметь эффект как :
while (!pred()) wait(lock);
Причина проверки предиката в цикле while заключается в том, что, помимо того факта, что условие уже может быть выполнено, поэтому ожидание не требуется, переменная условия может внезапно пробуждаться, даже если ей не дано указание сделать это.
Кроме того, нет причины, по которой сигнальный поток не должен использовать lock_guard по отношению к связанному мьютексу. Но мне не ясно, что вы пытаетесь сделать.