повысить общую проверку мьютекса, если он заблокирован в том же потоке

Когда я пишу многопоточные алгоритмы, я считаю, что для некоторых методов полезно иметь ожидание состояния мьютекса. У кого-то он уже заблокирован, у кого-то нет.

Я придумываю подход, как утверждать, что мьютекс уже должен быть заблокирован:

ASSERT(!mutex.try_lock_shared()); // assert if the mutex is not uniquely locked

ASSERT(!mutex.try_lock()); // assert if the mutex is not at least shared locked

Вопрос в том, как я мог бы сделать assert, который проверяет, что мьютекс не заблокирован ... из текущего потока. Например, если я сделаю это

     if (mutex.try_lock()) {
        mutex.unlock();
     } else {
        ASSERT(false); // the mutex is locked
     }

очевидно, время от времени он дает сбой только потому, что какой-то другой поток заблокировал его.


person gsf    schedule 26.03.2015    source источник
comment
Я пишу очень сложный многопоточный алгоритм с множеством методов, вызывающих друг друга. - лучший совет, который я могу дать здесь: сделайте это проще. Просто разбейте его на шаги более высокого уровня, чтобы вы мысленно знали, кто отвечает за блокировку. Рекурсивные мьютексы почти всегда являются запахом кода. Как и общие указатели, ими злоупотребляют вместо того, чтобы продумать ваш дизайн, чтобы сделать его простым.   -  person sehe    schedule 27.03.2015
comment
Очень сложным является состояние, которого я достиг после того, как сделал все это. Я не уверен, почему все предполагают, что то, что я спрашиваю, каким-то образом связано с реентерабельными мьютексами, когда я явно просил shared_mutex. Я хочу, как и любой хороший разработчик, когда я указываю ожидания метода, вместо комментария я мог бы добавить утверждение, которое быстрее проясняет, если что-то нарушает протокол.   -  person gsf    schedule 27.03.2015
comment
Я понял. Просто когда вы не можете объяснить, каким образом ваше конкретное приложение является сложным, это заставляет меня думать, что это может быть что-то вроде долга за дизайн. В противном случае я не вижу, насколько конструктивно/уместно даже упоминать об этой предполагаемой сложности в вопросе. Если вы не хотите, чтобы это имело какое-либо отношение к этому, вы можете просто удалить это из вопроса.   -  person sehe    schedule 27.03.2015
comment
Не уверен, почему вы считаете это вредным, но я избавляюсь от него, так как вы правы, он также не способствует.   -  person gsf    schedule 28.03.2015
comment
Просто запрограммируйте свои собственные мьютексы, которые имеют именно то поведение, которое вам нужно. Вы можете реализовать их, используя обычные мьютексы для защиты их внутреннего состояния. Например, ваша функция блокировки может сначала заблокировать обычный мьютекс, а затем установить для переменной, которая удерживает эту блокировку, идентификатор текущего потока. Это заставляет утверждения работать.   -  person David Schwartz    schedule 28.03.2015
comment
Еще одна причина наличия этой возможности — помощь в тестировании ситуаций, когда действия в потоке в заблокированной области занимают больше времени, чем ожидалось, и что эта непредвиденная задержка не приводит к тайм-аутам, зависанию и т. д. Путем добавления вызова sleep только тогда, когда блокировка фактически занята, не каждый раз, когда рекурсивная блокировка может быть заблокирована, вы не ужасно замедляете свою систему тестирования.   -  person Jason Harrison    schedule 27.10.2015


Ответы (1)


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

person Tim Brauer    schedule 26.03.2015
comment
Я не хочу повторно входить в мьютекс. Если мьютекс заблокирован, это будет означать ошибку. Я хотел бы, чтобы мне как можно скорее сообщили, что у меня ошибка в логике. - person gsf; 26.03.2015
comment
Попробуйте использовать рекурсивный мьютекс с флагом. Рекурсивный мьютекс позволит вам несколько раз блокировать один и тот же поток. Флаг будет обозначать, был ли он заблокирован ранее. Что-то вроде: boost::recursive_mutex::scoped_lock l(mtx_); if (flag_) { // handle error } flag_ = true; ... - person Tim Brauer; 27.03.2015