首页 > 解决方案 > 释放锁并取消一个死锁的 TPL 任务

问题描述

我正在尝试释放 TPL 任务中的锁,该任务卡在对线程不安全的第三方 COM 组件的调用中。

我需要释放锁,因为任务是可排队的(当组件恢复时,它必须可供其他排队的任务使用)

这是代码:

private Task RunQueueableTask()
{
    var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
    var cancellationToken = cancellationTokenSource.Token;

    return
        Task
            .Run(
                () =>
                {
                    Monitor.Enter(_lock);
                    {
                        try
                        {
                            cancellationToken.Register(() =>
                            {
                                Monitor.Exit(_lock);
                            }, true); //"true" ensures that the target syncContext is the active SynchronizationContext.Current

                            //Blocked thread unsafe third party COM component call
                            var result = ThirdPartyCOMComponent.Call();
                        }
                        finally
                        {
                            Monitor.Exit(_lock);
                        }
                    }
                }, cancellationToken)
            .ContinueWith(t =>
            {                       
                cancellationTokenSource.Dispose();
            });
}

然而,cancellationToken.Register 回调没有被调用,可能是因为它无法获取同步上下文。

现在我正在使用 Monitor.TryEnter 以便后续任务不会被阻止。

private static readonly object _lock = new object();

private Task RunQueueableTask()
{   
    var cancellationTokenSource = new CancellationTokenSource();
    var cancellationToken = cancellationTokenSource.Token;

    return
        Task
            .Run(
                () =>
                {
                    if (Monitor.TryEnter(_lock, TimeSpan.FromMinutes(5)))
                    {
                        try
                        {
                            //Blocked thread unsafe third party COM component call
                            var result = ThirdPartyCOMComponent.Call();
                        }
                        finally
                        {
                            Monitor.Exit(_lock);
                        }
                    }
                    else
                    {
                        cancellationTokenSource.Cancel();
                    }
                }, cancellationToken)
            .ContinueWith(t =>
            {                       
                cancellationTokenSource.Dispose();
            });
}

专家有什么建议吗?

标签: c#lockingtasktask-parallel-librarysynchronizationcontext

解决方案


推荐阅读