У меня есть приложение, которое асинхронно принимает события из API и может синхронно вызывать методы в этом API.Самый эффективный шаблон проектирования для обработки событий с блокировкой
Для обеспечения безопасности потоков мне нужна каждая синхронная функция, и каждый обработчик событий в моем приложении заблокирован.
Однако вызов метода API синхронно может привести к тому, что API поднимет события в другом потоке и дождитесь их обработки перед возвратом.
Таким образом, это может привести к тупиковой ситуации, поскольку API будет ждать обработки события для продолжения, но в моем классе объект синхронизации будет поражен двумя разными потоками, и программа зависает.
Моя идея состоит в том, чтобы вместо блокировки обработчиков событий попытаться заблокировать и если это невозможно (например, если событие вызвано синхронным вызовом другого потока) для буферизации события в насосе очереди/сообщения.
Сразу после освобождения блокировки при вызове синхронной функции я бы затем вызвал функцию ProcessPendingEvents()
, чтобы события могли обрабатываться без взаимоблокировки.
У вас есть какой-либо шаблон дизайна, который вы бы порекомендовали для такого рода ситуаций? Я открыт ко всему.
Вот простой пример, иллюстрирующий мою текущую предварительную реализацию. Я действительно стремиться к тому, класс, который будет вести себя в однопоточных образом как можно больше:
class APIAdapter {
readonly object AdapterLock = new object();
private readonly ConcurrentQueue<Tuple<object, EventArgs>> PendingEvents = new ConcurrentQueue<Tuple<object, EventArgs>>();
ExternalAPI API = new ExternalAPI();
APIAdapter() {
ExternalAPI.Data += ExternalAPI_Data;
}
public void RequestData() {
lock (this.AdapterLock) {
this.ExternalAPI.SynchronousDataRequest(); //Will cause the API to raise the Data event would therefore deadlock if I had a simple lock() in ExternalAPI_Data.
this.ProcessPendingEvents();
}
}
private void ExternalAPI_Data(object sender, EventArgs e) {
if (!Monitor.TryEnter(this.AdapterLock)) {
this.PendingEvents.Enqueue(Tuple.Create(sender, e));
return;
}
Console.Write("Received event.");
Monitor.Exit(this.AdapterLock);
}
private void ProcessPendingEvents() {
Tuple<object, EventArgs> ev;
while (this.PendingEvents.TryDequeue(out ev)) {
ExternalAPI_Data(ev.Item1, ev.Item2);
}
}
}
Посмотрите на класс '' ConcurrentQueue, это может быть посредником между потоками событий в этом случае. Альтернативно, [Rx] (http://msdn.microsoft.com/en-us/data/gg577609.aspx) может помочь здесь, так как он может принимать события как источники. –
Это то, что я использую с моей текущей реализацией. У меня хорошая модель дизайна или есть что-то совершенно другое, о чем я должен думать? –
Выглядит неплохо для меня. (Не нравится некоторые соглашения об именах, но на самом деле это не вопрос вопроса ...) –