Подтвердить что ты не робот

Почему блокировка std:: mutex не блокирует поток

Я написал следующий код, чтобы проверить мое понимание std::mutex

int main() {
    mutex m;
    m.lock();
    m.lock(); // expect to block the thread
}

А потом я получил system_error: device or resource busy. Разве не второй m.lock() должен блокировать поток?

4b9b3361

Ответ 1

От std::mutex:

Вызывающий поток не должен владеть мьютексом до блокировки вызова или try_lock.

и std::mutex::lock:

Если блокировка вызывается потоком, который уже владеет мьютексом, программа может зайти в тупик. В качестве альтернативы, если реализация может обнаружить тупик, может наблюдаться условие ошибки resource_deadlock_would_occur.

и предложение исключений:

Выбрасывает std:: system_error при возникновении ошибок, включая ошибки из базовой операционной системы, которые не позволят блокировке выполнить свои спецификации. Мьютекс не заблокирован в случае выброса любого исключения.

Поэтому он не должен блокировать поток. На вашей платформе реализация, похоже, обнаруживает, что поток уже является владельцем блокировки и создает исключение. Это может не произойти на других платформах, как указано в описаниях.

Ответ 2

Не второй m.lock() должен блокировать поток?

Нет, он дает поведение undefined. Второй m.lock() нарушает это требование:

С++ 11 30.4.1.2/7 Требуется: Если m имеет тип std::mutex или std::timed_mutex, вызывающий поток не имеет мьютекс.

Похоже, ваша реализация может обнаружить, что вызывающий поток владеет мьютексом и дает ошибку; другие могут блокироваться бесконечно или потерпеть неудачу другими способами.

Ответ 3

(std::mutex не упоминался в вопросе, когда я написал этот ответ.)

Это зависит от библиотеки мьютексов и типа мьютекса, которые вы используете, - вы не сказали нам. Некоторые системы предоставляют "рекурсивный мьютекс", который разрешается вызывать несколько раз, как это происходит, только если это происходит из того же потока (тогда у вас должно быть соответствующее количество разблокировок, прежде чем другой поток сможет его заблокировать), другие библиотеки считают это ошибкой и может потерпеть неудачу изящно (как у вас) или иметь поведение undefined.