【发布时间】:2013-11-26 17:01:48
【问题描述】:
我有一个应用程序从 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<T>类,在这种情况下它可以是事件流之间的中介。或者,Rx 可能会在这里提供帮助,因为它可以将事件作为源。 -
这是我在当前实现中使用的。我有一个好的设计模式还是我应该考虑完全不同的东西?
-
对我来说看起来不错。 (不喜欢某些命名约定,但这不是问题的重点......)
-
您特别不喜欢哪种命名约定?我总是很乐意改进它们。
-
C# 中的约定是字段以小写字母开头,以区别于类型、方法和常量。此外,超过两个字符的首字母缩写词被视为单词。所以它“应该”是
ExternalApi api = new ExternalApi();。但正如威尔所说,这并不重要。
标签: c# multithreading events design-patterns message-pump