Очевидно, что запуск событий внутри блокировки (т. е. в критической секции) может привести к взаимоблокировкам из-за возможности того, что обработчик событий может заблокировать какую-либо асинхронную операцию, которая также должна получить ту же блокировку. Теперь, с точки зрения дизайна, есть два возможных решения, которые приходят мне на ум:
Если необходимо запустить событие внутри блокировки, всегда запускайте событие асинхронно. Это можно сделать, например, с помощью ThreadPool, если порядок запуска событий не имеет значения. Если порядок событий должен быть сохранен, то можно использовать один поток запуска событий для запуска событий по порядку, но асинхронно.
Классу/библиотеке, запускающей события, не нужно предпринимать никаких необходимых мер предосторожности, чтобы предотвратить взаимоблокировку, и просто запускать событие внутри блокировки. В этом случае ответственность за асинхронную обработку события лежит на обработчике событий, если он выполняет блокировку (или любую другую операцию блокировки) внутри обработчика событий. Если обработчик события не соответствует этому правилу, он должен пострадать от последствий в случае возникновения взаимоблокировки.
Честно говоря, я считаю, что второй вариант лучше с точки зрения принципа разделения ответственности, поскольку код запуска события не должен догадываться, что может или не может делать обработчик события.
Однако на практике я склоняюсь к первому пути, поскольку второй вариант, похоже, сводится к тому, что каждый обработчик событий должен теперь выполнять весь код обработки событий асинхронно, поскольку в большинстве случаев неясно, выполняется ли какая-либо серия вызовов. выполняет операцию блокировки или нет. Для сложных обработчиков событий отслеживание всех возможных путей (и, более того, отслеживание их по мере развития кода) — определенно непростая задача. Поэтому решение проблемы в одном месте (там, где запускается событие) представляется предпочтительным.
Мне интересно посмотреть, есть ли другие альтернативные решения, которые я мог упустить, и какие возможные преимущества/недостатки и подводные камни можно отнести к каждому возможному решению.
Есть ли лучшая практика для такой ситуации?