У меня есть несколько потоков, обновляющих один массив в узких циклах. (10 потоков на двухъядерном процессоре при примерно 100 000 обновлений в секунду). Каждый раз массив обновляется под защитой мьютекса (WaitForSingleObject/ReleaseMutex). Я заметил, что ни один поток никогда не выполняет два последовательных обновления массива, что означает, что должен быть какой-то выход, связанный с синхронизацией. Это означает, что каждую секунду происходит около 100 000 переключений контекста, что кажется неоптимальным. Почему это происходит?
Почему я получаю переключение контекста потока каждый раз, когда я синхронизируюсь с мьютексом?
Ответы (2)
Проблема здесь в том, что существует порядок всех ожидающих потоков.
Каждый поток, заблокированный в WaitForSingleObject, помещается в очередь, а затем приостанавливается планировщиком, чтобы больше не отнимать время выполнения. Когда мьютекс освобождается, планировщик возобновляет выполнение одного из ожидающих потоков. Неизвестно, каков точный порядок, в котором потоки пробуждаются из очереди, но во многих случаях это будет простой порядок «первым пришел — первым вышел».
Что происходит сейчас, так это то, что если тот же поток освобождает мьютекс, а затем выполняет другой объект WaitForSingleObject для того же мьютекса, он будет повторно вставлен в очередь, и весьма маловероятно, что он будет вставлен в начало очереди, если уже есть другие потоки ожидания. Это имеет смысл, так как разрешение ему перейти в начало очереди может привести к голоданию других потоков. Таким образом, планировщик, вероятно, просто приостановит его и вместо этого разбудит поток, который находится в начале очереди.
WaitForSingleObject
, и уже есть другие потоки, ожидающие того же мьютекса.
- person ComicSansMS; 14.06.2013
WaitForSingleObject
, будет разрешен возврат раньше, но это всего лишь оптимизация. Однако, если он вернется раньше, если есть ожидающие потоки, это приведет к несправедливому планированию. Первый случай — вопрос эффективности, второй — корректности.
- person ComicSansMS; 14.06.2013
Думаю, это из-за мультипроцессора.
Когда первый поток (работающий на первом процессоре) освобождает мьютекс, второй поток (на втором процессоре) его получает, затем, когда первый поток пытается получить мьютекс, он не может. Когда мьютекс окончательно освобождается вторым потоком, он берется третьим потоком (на первом процессоре).
WaitForSingleObject
находятся в очереди, поэтому поток будет после всех других потоков после того, как он вызовет ReleaseMutex
. Вот почему я спросил @FunkyOordvork, есть ли у него доступ к одноядерной машине.
- person Kevin MOLCARD; 14.06.2013
SetThreadAffinityMask
< /a> должно помочь.
- person ComicSansMS; 14.06.2013
WaitForSingleObject
? В частности, какой тайм-аут вы даете ему? Если вы используете INFINITE, я думаю, это будет ожидаемое поведение - person Kevin MOLCARD   schedule 14.06.2013