两次调用Dispatcher.Invoke()时出现死锁

时间:2014-10-15 20:37:05

标签: c# wpf deadlock invoke dispatcher

我有两个调度员:

dispatcher1
dispatcher2

现在,当我打电话时(这是我的复杂代码的简化示例):

            var ret = dispatcher1.Invoke(() => {
                return dispatcher2.Invoke(() => {
                    return new object();
                });
            });

我将陷入僵局。

的召唤
dispatcher1.Invoke()

正在等待

DispatcherSynchronizationContext.Wait()

以及调用

后的调度程序2
dispatcher2.Invoke()

正在等待

DispatcherSynchronizationContext.Wait

我无法将Invoke-Calls更改为异步调用(BeginInvoke),因为我需要结果。

这不是.NET 4.0的情况 - 只是因为我已经改为.NET 4.5。

有没有办法解决这个问题?

1 个答案:

答案 0 :(得分:3)

这是一个非常非常糟糕的解决方案,你不应该使用它。如初。

但如果您想生活危险,请尝试使用下面的Invoke扩展方法替换您的InvokeAndPump来电。 (不要在项目中替换Invoke的每次调用 - 只是问题中的问题。)

public static class DispatcherExtensions
{
    public static T InvokeAndPump<T>(
        this Dispatcher dispatcher,
        Func<T> function,
        DispatcherPriority priority = DispatcherPriority.Normal)
    {
        if (dispatcher == null)
            throw new ArgumentNullException("dispatcher");
        if (function == null)
            throw new ArgumentNullException("function");

        // If you've found this code in your project, you are doomed.  <3

        Action wait, notify;

        var currentDispatcher = Dispatcher.FromThread(Thread.CurrentThread);
        if (currentDispatcher != null)
        {
            var frame = new DispatcherFrame();

            wait = () => Dispatcher.PushFrame(frame);
            notify = () => frame.Continue = false;
        }
        else
        {
            var waitEvent = new ManualResetEventSlim(false);

            wait = waitEvent.Wait;
            notify = waitEvent.Set;
        }

        var error = default(Exception);
        var result = default(T);

        dispatcher.BeginInvoke(
            priority,
            new Action(
                () =>
                {
                    try { result = function(); }
                    catch (Exception e) { error = e; }
                    finally { notify(); }
                }));

        // Hold on to your butts...

        wait();

        if (error != null)
            throw new TargetInvocationException(error);

        return result;
    }
}

但是,严肃地说:天堂帮助任何使用它并期望它可靠地工作的人。我只是出于好奇而发布它,因为我是邪恶的。主要是邪恶。