为什么.NET 4.0中的Monitor.Wait和PulseAll不起作用

时间:2014-07-09 08:18:26

标签: c# .net multithreading

在我们的Legacy项目中,我们使用以下代码进行异步操作:

public interface IAsyncOperation
{
    OperationToken Token { get; }
    bool IsCompleted { get; }
    Exception Exception { get; }
    bool Wait(int timeout);
}

/// <summary>
/// Asynchronous operation that may be executed on a separate thread.
/// IsCompleted and Exception would be synchronized after invoking Wait.
/// </summary>
public abstract class AsyncOperation : IAsyncOperation
{
    protected readonly object CompletionLock = new object();
    private volatile bool isCompleted; // volatile in order not to change the order of writing Exception and Result

    protected AsyncOperation(bool isCompleted = false)
    {
        IsCompleted = isCompleted;
        Token = OperationToken.New();
    }

    public OperationToken Token { get; protected set; }

    public bool IsCompleted
    {
        get { return isCompleted; }
        protected set { isCompleted = value; }
    }

    public Exception Exception { get; protected set; }

    public bool Wait(int timeout)
    {
        if (!IsCompleted)
        {
            lock (CompletionLock)
            {
                if (!IsCompleted)
                {
                    Monitor.Wait(CompletionLock, timeout);
                }
            }
        }

        return IsCompleted;
    }

    protected void Complete()
    {
        RequireNotCompleted();
        lock (CompletionLock)
        {
            RequireNotCompleted();
            IsCompleted = true;
            Monitor.PulseAll(CompletionLock);
        }
    }

    protected void RequireNotCompleted()
    {
        if (IsCompleted)
        {
            throw new InvalidOperationException("The operation was already completed");
        }
    }

    protected void Complete(Exception exception)
    {
        RequireNotCompleted();
        lock (CompletionLock)
        {
            RequireNotCompleted();
            Exception = exception;
            IsCompleted = true;
            Monitor.PulseAll(CompletionLock);
        }
    }
}

总是工作正常。将项目迁移到.NET 4.5.1后,我们看起来有以下问题:

  1. 我们创建了一个Wait(Timeout.Inifinte),我们知道一个操作已经完成但是Wait的线程正在等待...如果我们设置超时而不是总是在超时后离开该方法
  2. 在分析器中,我们看到可能Complete()等待进入锁定状态 - Monitor.Wait是否没有回锁?
  3. enter image description here

    以下是在工作线程中执行的AsyncCommand的实现:

    internal class AsyncCommand : AsyncOperation
    {
        private readonly Action<OperationToken> command;
    
        public AsyncCommand(Action<OperationToken> command)
        {
            command.ThrowIfNull("command");
            this.command = command;
        }
    
        public void Execute()
        {
            RequireNotCompleted();
            try
            {
                command(Token);
                Complete();
            }
            catch (Exception ex)
            {
                Complete(ex);
            }
        }
    }
    

    您是否看到以下代码有任何问题? 什么可能导致这些问题?

    上面的实现是正确的。我们遇到了一些与.NET远程连接有关的问题......

0 个答案:

没有答案