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