Краткая версия: Как я могу освободить несколько блокировок из одного потока, не будучи выгруженным на полпути?Освобождение нескольких замков, не вызывающих инверсию приоритета
У меня есть программа, предназначенная для работы на N-ядерном компьютере. Он состоит из одного основного потока и N рабочих потоков. Каждый поток (включая основной поток) имеет семафор, на котором он может блокироваться. Обычно каждый рабочий поток блокируется при уменьшении его семафора, а основной поток работает. Время от времени основной поток должен разбудить рабочие потоки, чтобы делать свое дело в течение определенного времени, а затем блокировать на своем собственном семафоре, ожидая, что все они вернутся спать. Например:
def main_thread(n):
for i = 1 to n:
worker_semaphore[i] = semaphore(0)
spawn_thread(worker_thread, i)
main_semaphore = semaphore(0)
while True:
...do some work...
workers_to_wake = foo()
for i in workers_to_wake:
worker_semaphore[i].increment() # wake up worker n
for i in workers_to_wake:
main_semaphore.decrement() # wait for all workers
def worker_thread(i):
while True:
worker_semaphore(i).decrement() # wait to be woken
...do some work...
main_semaphore.increment() # report done with step
Все хорошо и хорошо. Проблема в том, что один из разбуженных рабочих может в конечном итоге вытеснить основной поток на полпути через пробуждение рабочих: это может произойти, например, когда планировщик Windows решает повысить приоритет этого работника. Это не приводит к тупиковой ситуации, но это неэффективно, потому что оставшаяся часть нитей остается спальной до тех пор, пока вытесняющий работник не завершит свою работу. Это в основном приоритетная инверсия, причем основной поток ожидает один из рабочих, а некоторые рабочие потоки ждут основного потока.
Возможно, я смогу найти для этого хакеры с ОС и планировщиками, такие как отключение повышения приоритета под Windows, а также поиск приоритетов потоков и сходства процессоров, но мне бы хотелось что-то межплатформенное и надежное и чистый. Итак: Как я могу разбудить кучу нитей атомарно?
Предпосылка этого вопроса неверна. Это неэффективно. Этот поток готов к запуску, поэтому он будет работать, если система не сможет больше разместить готовые к запуску потоки. Если система не может разместить больше готовых к запуску потоков, нет никакой спешки, чтобы сделать больше потоков готовыми к запуску. –
@DavidSchwartz только для систем с общими очередями.Системы с чередовыми очередями запуска могут запускать потоки с более низким приоритетом вместо планирования основного потока или в настоящее время разблокированных рабочих потоков. Даже если для аффинности потоков настроены, чтобы уменьшить это, основной поток может по-прежнему разделять близость с одним из рабочих потоков. – Sneftel
Ну, конечно, если вы настроите плохо, они будут плохо работать. Решение заключается не в том, чтобы плохо настроить ситуацию, а чтобы не пытаться смягчить вред плохой настройки. Все, что вам нужно сделать, это не красить себя в угол. По умолчанию обрабатываются такие вещи почти идеально. –