程序挂起可能是由于 lambda 关闭或调度程序问题
Program hangs possibly due to lambda closures or dispatcher issue
我实现了一个实验性的轻量级内存消息总线,收件人可以通过我在下面粘贴的 Subscribe()
方法订阅消息。
发件人可以发送消息,消息总线将调用内部回调 internalCallback
。在调用回调之前,消息可能会被深度克隆并编组到 UI 线程中。
这就是我的问题所在:当我注释掉 UI 调度程序时(如下面的代码片段中所做的那样),回调将被正确调用。调度程序处于活动状态时,整个应用程序会挂起(不会抛出 运行 时间错误)。更让我困惑的是,当我 运行 在 UI 线程上调用方法时,下面的整个代码工作得很好。但是现在整个框架也可能在不同的 tasks/threads 上发送消息,这就是问题出现的时候。
我应该研究或调整什么?
谢谢
public void Subscribe<T>(string subscriberId, string topic, Action<string, T> callback, bool returnOnUiThread, bool makeDeepCopy, bool catchAll)
{
//create new peer connection if it does not yet exist
if (!_peerConnections.ContainsKey(subscriberId))
{
var newPeer = new PeerConnection(subscriberId)
{
ConnectionStatus = PeerConnectionStatus.Connected,
CreationTimeStamp = DateTime.Now,
LastAliveTimeStamp = DateTime.Now
};
_peerConnections.Add(subscriberId, newPeer);
}
var internalCallBack = new Action<string, object>((header, msg) =>
{
//make a deep copy via serialization if requested
if (makeDeepCopy == true)
{
//try deep clone
var serializedObject = Serializers.JsonStringFromObject(msg);
msg = Serializers.ObjectFromJsonString<T>(serializedObject);
}
var handle = callback;
handle(header, (T)msg);
////return on ui thread if requested
//if (returnOnUiThread == true)
//{
// Application.Current.Dispatcher.Invoke(() =>
// {
// var handle = callback;
// handle(header, (T)msg);
// });
//}
//else
//{
// var handle = callback;
// handle(header, (T)msg);
//}
});
//adding subscription to collection
var subscription = new Subscription(subscriberId, topic, internalCallBack, catchAll);
_subscriptions.Add(subscription);
}
您应该使用 BeginInvoke
,因为 Invoke
会导致死锁。 Invoke
是一种锁,所以它会等待,阻塞当前线程直到操作完成。 BeginInvoke
将请求放到 Windows 消息泵 上,稍后将由 UI 线程处理,而不会阻塞工作线程。
即使 Windows GUI 不是多线程的,您仍然可以将其死锁。查看下面的文章。
更多
- Multithreaded toolkits: A failed dream? Blog,甲骨文,2004 年 10 月 19 日
我实现了一个实验性的轻量级内存消息总线,收件人可以通过我在下面粘贴的 Subscribe()
方法订阅消息。
发件人可以发送消息,消息总线将调用内部回调 internalCallback
。在调用回调之前,消息可能会被深度克隆并编组到 UI 线程中。
这就是我的问题所在:当我注释掉 UI 调度程序时(如下面的代码片段中所做的那样),回调将被正确调用。调度程序处于活动状态时,整个应用程序会挂起(不会抛出 运行 时间错误)。更让我困惑的是,当我 运行 在 UI 线程上调用方法时,下面的整个代码工作得很好。但是现在整个框架也可能在不同的 tasks/threads 上发送消息,这就是问题出现的时候。
我应该研究或调整什么?
谢谢
public void Subscribe<T>(string subscriberId, string topic, Action<string, T> callback, bool returnOnUiThread, bool makeDeepCopy, bool catchAll)
{
//create new peer connection if it does not yet exist
if (!_peerConnections.ContainsKey(subscriberId))
{
var newPeer = new PeerConnection(subscriberId)
{
ConnectionStatus = PeerConnectionStatus.Connected,
CreationTimeStamp = DateTime.Now,
LastAliveTimeStamp = DateTime.Now
};
_peerConnections.Add(subscriberId, newPeer);
}
var internalCallBack = new Action<string, object>((header, msg) =>
{
//make a deep copy via serialization if requested
if (makeDeepCopy == true)
{
//try deep clone
var serializedObject = Serializers.JsonStringFromObject(msg);
msg = Serializers.ObjectFromJsonString<T>(serializedObject);
}
var handle = callback;
handle(header, (T)msg);
////return on ui thread if requested
//if (returnOnUiThread == true)
//{
// Application.Current.Dispatcher.Invoke(() =>
// {
// var handle = callback;
// handle(header, (T)msg);
// });
//}
//else
//{
// var handle = callback;
// handle(header, (T)msg);
//}
});
//adding subscription to collection
var subscription = new Subscription(subscriberId, topic, internalCallBack, catchAll);
_subscriptions.Add(subscription);
}
您应该使用 BeginInvoke
,因为 Invoke
会导致死锁。 Invoke
是一种锁,所以它会等待,阻塞当前线程直到操作完成。 BeginInvoke
将请求放到 Windows 消息泵 上,稍后将由 UI 线程处理,而不会阻塞工作线程。
即使 Windows GUI 不是多线程的,您仍然可以将其死锁。查看下面的文章。
更多
- Multithreaded toolkits: A failed dream? Blog,甲骨文,2004 年 10 月 19 日