Какая разница между "мьютексом" и "блокировкой"?
Я очень смущен разницей между блокировкой и мьютексом. В Boost docs говорится:
Типы блокировки
- Шаблон класса lock_guard
- Шаблон класса unique_lock
- Шаблон класса shared_lock
- Шаблон класса upgrade_lock
- Шаблон класса upgrade_to_unique_lock
- Класс, специфичный для Mutex scoped_try_lock
Типы Mutex
- Мьютекс класса
- Typedef try_mutex
- Класс timed_mutex
- Класс recursive_mutex
- Typedef recursive_try_mutex
- Класс recursive_timed_mutex
- Класс shared_mutex
В другой статье я вижу такие функции, как
boost::shared_mutex _access;
void reader()
{
boost::shared_lock< boost::shared_mutex > lock(_access);
// do work here, without anyone having exclusive access
}
void conditional_writer()
{
boost::upgrade_lock< boost::shared_mutex > lock(_access);
// do work here, without anyone having exclusive access
if (something) {
boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock);
// do work here, but now you have exclusive access
}
// do more work here, without anyone having exclusive access
}
Обновленные вопросы
- Может ли кто-нибудь предложить некоторые пояснения между "мьютексом" и "блокировкой"?
- Необходимо ли создать shared_lock для shared_mutex?
Что произойдет, если я создам unique_lock для shared_mutex?
- Или, если я создаю shared_lock для мьютекса, означает ли это, что мьютекс может
не разделяться между несколькими потоками?
Ответы
Ответ 1
A mutex - объект синхронизации. Вы получаете блокировку на мьютексе в начале раздела кода и освобождаете его в конце, чтобы гарантировать, что ни один другой поток не будет обращаться к тем же данным одновременно. Мьютекс обычно имеет продолжительность жизни, равную времени жизни данных, которые он защищает, и что к одному мьютексу обращаются несколько потоков.
Объект блокировки - это объект, который инкапсулирует эту блокировку. Когда объект строится, он приобретает замок на мьютексе. Когда он разрушен, блокировка освобождается. Обычно вы создаете новый объект блокировки для каждого доступа к общим данным.
Ответ 2
Мьютекс - это объект, который можно заблокировать. Замок - это объект, который
поддерживает замок. Чтобы создать блокировку, вам нужно передать мьютекс.
Ответ 3
Замки могут обеспечивать взаимное исключение, но не синхронизацию условий. В отличие от семафора блокировка имеет владельца, а собственность играет важную
роль в поведении блокировки
example -
class lockableObject { public void F() {
mutex.lock(); ...; mutex.unlock();
}
public void G() {
mutex.lock(); ...; F(); ...; mutex.unlock();
}
private mutexLock mutex; }
// method G() calls method F()
Блокировка мьютекса в классе lockableObject используется для преобразования методов F() и G() в критические разделы. Таким образом, только один поток за один раз может выполняться внутри метода lockableObject. Когда поток вызывает метод G(), мьютекс заблокирован. Когда метод G() вызывает метод F(), mutex.lock() выполняется в F(), но вызывающий поток не блокируется, поскольку он уже владеет мьютексом. Если мьютекс был двоичным семафором вместо блокировки, вызов из G() в F() блокировал бы вызывающий поток, когда mutex.P() выполнялся в F(). (Напомним, что дополнения операций P() и V() на двоичном семафоре должны чередоваться.) Это создало бы тупик, поскольку никакие другие потоки не могли бы выполняться внутри F() или G().
Это различия между блокировками и двоичными семафорами:
1 Для двоичного семафора, если два вызова выполняются в P() без какого-либо промежуточного вызова V(), второй вызов будет блокироваться. Но поток, который владеет блокировкой и запрашивает право собственности, не блокируется. (Остерегайтесь того факта, что блокировки не всегда рекурсивные, поэтому перед использованием блокировки проверьте документацию.)
2 Владелец для последовательных вызовов lock() и unlock() должен быть тем же самым потоком. Но последовательные вызовы P() и V() могут выполняться разными потоками.