由于lambda闭包或调度程序问题,程序可能会挂起
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了由于lambda闭包或调度程序问题,程序可能会挂起相关的知识,希望对你有一定的参考价值。
我实现了一个实验性的轻量级内存消息总线,接收者可以通过我粘贴在下面的Subscribe()
方法订阅消息。
发件人可以发送消息,消息总线将调用内部回调internalCallback
。在调用回调之前,可以将消息进行深度克隆并封送到UI线程上。
这就是我出现问题的地方:当我注释掉UI调度程序时(如下面的代码片段所示),然后正确调用回调。在调度程序处于活动状态时,整个应用程序将挂起(不会引发运行时错误)。让我更加困惑的是,当我在UI线程上运行调用方法时,整个下面的代码工作得非常好。但是现在整个框架也可以在不同的任务/线程上发送消息,这就是出现问题的时候。
我应该研究或调整什么?
谢谢
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不是多线程的,您仍然可以使其死锁。查看下面的文章。
更多
- 2004年10月19日,Oracle,Multithreaded toolkits: A failed dream? Blog
以上是关于由于lambda闭包或调度程序问题,程序可能会挂起的主要内容,如果未能解决你的问题,请参考以下文章
调试 Oracle PL/SQL WEB 应用程序会挂起浏览器和开发工具
即使所有退出事件成功触发,Electron 应用程序也会挂起