Совместная / не упреждающая обработка потоков, позволяющая избежать взаимоблокировок?
-
22-09-2019 - |
Вопрос
Есть какие-нибудь творческие идеи, чтобы избежать взаимоблокировок при выходе или перейти в режим ожидания с совместной / не упреждающей многозадачностью без выполнения потока O / S.Перейти в режим ожидания (10)?Обычно вызов yield или sleep возвращает запрос в планировщик для выполнения других задач.Но иногда это может привести к тупиковым ситуациям.
Некоторая предыстория:
Этому приложению очень нужна скорость, и на данный момент оно чрезвычайно быстрое по сравнению с другими системами в той же отрасли.Одним из методов повышения скорости является совместное / непередавающее потокование, а не стоимость переключения контекста из потоков O / S.
На высоком уровне разрабатывается менеджер приоритетов, который вызывает задачи в зависимости от приоритета и времени обработки.Каждая задача выполняет одну "итерацию" работы и возвращается, чтобы снова дождаться своей очереди в очереди приоритетов.
Сложная вещь с непередавающей обработкой потоков заключается в том, что делать, когда вы хотите, чтобы конкретная задача остановилась в середине работы и дождалась какого-то другого события от другой задачи, прежде чем продолжить.
В этом случае у нас есть 3 задачи, A B и C, где A - контроллер, который должен синхронизировать активность B и C.Во-первых, A запускает как B, так и C.Затем B выдает результат, так что вызывается C.Когда C уступает, A видит, что они оба неактивны, и решает, что B пора запускать, но для C пока нет времени.Ну, а B теперь застрял в yield, который вызвал C, так что он никогда не сможет запуститься.
Решение 2
Что ж, понял, что идеальным решением для этого было бы, если бы язык C # поддерживал истинные "продолжения", чтобы расширить стек и продолжить с того места, где остановились позже.
В отсутствие этого мы делаем нашу собственную импровизированную замену, разрешая задачам в этой ситуации устанавливать флаг "isInterrupted" равным true и возвращать - тем самым разматывая stack.
Затем, когда планировщик захочет снова запланировать время обработки для этой задачи, он увидит isInterrupted и пропустит обработку, которая уже была выполнена, чтобы перейти прямо к месту прерывания, используя простой оператор if.
С уважением,, Уэйн
Другие советы
Я думаю, что, вероятно, самый чистый способ справиться с этим — отделить передачу (поток, решивший, что он уже достаточно обработал) от блокировки (ожидание определенного события).Это позволяет относительно легко дать время потокам, которые уступили место, но избежать тупиковой ситуации из-за попытки запустить заблокированный поток.Как правило, вы хотите выполнить топологическую сортировку того, какой поток блокирует какой другой поток, чтобы вы могли дать время потокам, которые ожидают другие.Это должно дать DAG — любой цикл на графике указывает на тупик.