Кооперативная / не упреждающая многопоточность, позволяющая избежать взаимоблокировок?

Любые креативные идеи, чтобы избежать взаимоблокировок на выходе или в спящем режиме с помощью кооперативной / не вытесняющей многозадачности без выполнения O/S Thread.Sleep(10)? Обычно вызов yield или sleep перезвонит в планировщик для запуска других задач. Но иногда это может привести к тупикам.

Немного предыстории:

Это приложение имеет огромную потребность в скорости и пока очень быстро по сравнению с другими системами в той же отрасли. Одним из методов ускорения является кооперативная / не вытесняющая многопоточность, а не стоимость переключения контекста из потоков O / S.

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

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

В этом случае у нас есть 3 задачи, A B и C, где A - контроллер, который должен синхронизировать действия B и C. Сначала A запускает и B, и C. Затем B возвращает результат, так что C вызывается. Когда C уступает, A видит, что они оба неактивны, решает, что пришло время запустить B, но еще не пришло время C. Скважина B теперь застряла в добыче, которая называется C, поэтому она никогда не сможет работать.

2 ответа

Решение

Что ж, мы поняли, что идеальным решением для этого было бы, если бы язык C# поддерживал истинные "продолжения", расширяющие стек и продолжавшие там, где их остановили позже.

В отсутствие этого мы производим нашу собственную временную замену, позволяя задачам в этой ситуации установить флаг isInterrupted в true и вернуть - таким образом, раскручивая стек.

Затем, когда планировщик захочет снова запланировать время обработки для этой задачи, он увидит isInterrupted и пропустит уже выполненную обработку, чтобы перейти прямо к месту прерывания, используя простой оператор if.

С уважением, Уэйн

Я думаю, что, вероятно, самый чистый способ справиться с этим - отделить выход (поток, решивший, что он достаточно долго обработал) от блокировки (ожидание определенного события). Это позволяет относительно легко уделять время потокам, которые уступили, но избегать тупиковой ситуации при попытке запустить заблокированный поток. Как правило, вы хотите выполнить топологическую сортировку того, какой поток блокирует другой поток, чтобы вы могли дать время тем потокам, которые ожидают другие. Это должно дать DAG - любой цикл на графике указывает на тупик.

Другие вопросы по тегам