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

Puteread Mutex: pthread_mutex_unlock() потребляет много времени

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

Когда я использую профилировщик Intel VTune для профилирования своей программы, я обнаружил, что производитель и потребитель тратят много времени на pthread_mutex_unlock. Я не понимаю, почему это произошло. Я думаю, что потоки могут долго ждать, прежде чем они смогут получить мьютекс, но освобождение мьютекса должно быть быстрым, верно?

Ниже приведен снимок от Intel VTune. Он показывает коды, где потребитель пытается извлечь элемент из буфера и время, затрачиваемое на каждую строку кода.

Мой вопрос в том, почему у pthread_mutex_unlock есть такие накладные расходы? Является ли проблема с самим мьютексом pthread или с тем, как я его использую? enter image description here

4b9b3361

Ответ 1

Функция pthread_mutex_unlock() должна освобождать объект mutex, на который ссылается mutex. Но способ освобождения мьютекса зависит от атрибута типа mutex. Если есть потоки, заблокированные в объекте mutex, на которые ссылается mutex, когда вызывается pthread_mutex_unlock(), в результате чего становится доступным мьютекс, политика планирования должна определять, какой поток должен получить мьютекс.

Если тип мьютекса PTHREAD_MUTEX_NORMAL, обнаружение взаимоблокировки не должно предоставляться. Попытка заблокировать мьютекс вызывает тупик. Если поток пытается разблокировать мьютекс, который он не заблокировал, или мьютекс, который разблокирован, результаты поведения undefined.

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

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

Если тип мьютекса PTHREAD_MUTEX_DEFAULT, попытка рекурсивного блокирования мьютекса приводит к поведению undefined. Попытка разблокировать мьютекс, если он не был заблокирован вызывающим потоком, приводит к поведению undefined. Попытка разблокировать мьютекс, если он не заблокирован, приводит к поведению undefined.

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