Иногда может возникнуть необходимость доступа к нескольким ресурсам сразу. При этом возникает затруднение, когда два потока пытаются захватить оба ресурса, но запирают соответствующие мьютексы в различном порядке.
В приведенном ниже примере, два потока запирают мьютексы 1 и 2, и тогда тупик при попытке запереть другой мьютекс:
/* использует ресурс 1 */ | /* использует ресурс 2 */
pthread_mutex_lock(&m1); | pthread_mutex_lock(&m2);
/* теперь захватывает | /* теперь захватывает
ресурсы 2 + 1 */ | ресурсы 1 + 2 */
pthread_mutex_lock(&m2); | pthread_mutex_lock(&m1);
Если блокировка всегда выполняется в указанном порядке, тупик не возникнет. Однако, эта техника может использоваться не всегда. Иногда требуется запирать мьютексы в другом порядке, чем предписанный.
Чтобы предотвратить тупик в этой ситуации, лучше использовать функцию pthread_mutex_trylock(). Один из потоков должен освободить свой мьютекс, если он обнаруживает, что может возникнуть тупик.
Ниже проиллюстрирован подход условной блокировки:
Поток 1:
pthread_mutex_lock(&m2);
/* нет обработки */
pthread_mutex_unlock(&m2);
pthread_mutex_unlock(&m1);
pthread_mutex_lock(&m2);
if(pthread_mutex_trylock(&m1)==0)
/* захват! */
break;
/* уже заперт */
pthread_mutex_unlock(&m2);
}
/* нет обработки */
pthread_mutex_unlock(&m1);
pthread_mutex_unlock(&m2);