由于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不是多线程的,您仍然可以使其死锁。查看下面的文章。

更多

以上是关于由于lambda闭包或调度程序问题,程序可能会挂起的主要内容,如果未能解决你的问题,请参考以下文章

调试 Oracle PL/SQL WEB 应用程序会挂起浏览器和开发工具

为啥打开 mkfifo 管道时我的程序会挂起?

从 PHP 执行程序会挂起 APACHE

即使所有退出事件成功触发,Electron 应用程序也会挂起

为啥我的自托管 NancyFX 应用程序在通过 HTTPS 运行时会挂起?

在应用程序内使用 html+jquery 的 Android webview 有时会挂起