У меня есть приложение, в котором у меня есть общий ресурс (система движения), к которому могут обращаться несколько клиентов. У меня есть отдельные Операции, которые требуют доступа к системе в течение всего хода, и которые должны бросать "Занятые" исключения, если в то же время запрашиваются конфликтующие операции. У меня также есть Секвенсоры, которым необходимо получить эксклюзивный доступ к системе Motion для выполнения нескольких Операций, перемежающихся с другими действиями; в течение всей последовательности никакие другие клиенты не смогут запускать Операции.
Я традиционно обращался к этому, используя Thread-affinity, так что Thread может запрашивать эксклюзивный доступ и выполнять блокирующие вызовы, соответствующие операциям. Хотя Thread имеет доступ, никакие другие Threads не могут использовать ресурс. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что я перешел к внедрению моей системы с использованием шаблонов async/await, чтобы обеспечить реализацию более чистого секвенсора. Проблема в том, что теперь мой секвенсор не всегда работает в одном потоке; активный поток может меняться в ходе обратных вызовов, поэтому уже нелегко определить, действительно ли я в допустимом контексте, чтобы продолжать выполнять операции. Один из примечаний состоит в том, что некоторые из самих Операций состоят из ожиданий, что означает, что обе последовательности и отдельные операции могут охватывать несколько потоков.
Мой вопрос: знает ли кто-нибудь хороший шаблон для получения эксклюзивного доступа при наличии переключения потоков из-за асинхронного/ожидающего?
Для справки, несколько вещей, которые я рассмотрел:
-
Я мог бы создать настраиваемый SynchronizationContext, который будет маршировать все вызовы секвенсера в течение продолжительности последовательности до одного потока. Это дает мне возможность повторно использовать мой существующий код управления доступом к потоку. Недостатком является то, что для этого потребуется выделение Thread, когда я выполняю либо последовательность, либо операцию (поскольку операции могут также охватывать несколько потоков.)
-
Создайте доступный токен доступа, чтобы перейти к методам операции, чтобы доказать, что вы получили доступ. Это имеет недостаток в раздувании методов с помощью параметра токена.
-
Используйте подход токена доступа из (2), но создайте реализацию дублирующего интерфейса для интерфейса операций, чтобы обертка могла быть создана с использованием "купленного" токена. Это создает некоторый уродливый код клея, но он очищает код секвенсора, так что ему больше не нужно передавать токен каждому методу.