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

更多