简体   繁体   中英

Locking async method in windows phone 7

I am uploading data to dropbox on a button Command using custom method name UploadDataToDropbboxAsync(); i am using this method on like this.

 RelayCommand _navigateToDropBoxUploadCommand;
    public ICommand NavigateToDropBoxUploadCommand
    {
        get
        {
            return _navigateToDropBoxUploadCommand = _navigateToDropBoxUploadCommand ?? new RelayCommand(
                    async () =>
                    {
                        await UploadDataToDropbox("sandbox");
                    });
        }
    }

so when i click the button multiple time before wait for data to be uploaded then thr is multiple simultaneous uploads happening. so i wanted to put a lock on this method such that it will not be called again before first upload finished. any kind of help is appreciated.

I would not use locking for this. For one, you're only dealing with one thread--the UI thread (at least in terms of the locking--as what you're really asking is to lock-out the UI thread from running this command). Another, it's heavy-weight compared do what would be a better way of dealing with this.

I would simply disable the button before the Async and re-enable it afterwards. For example:

return _navigateToDropBoxUploadCommand = _navigateToDropBoxUploadCommand ?? new RelayCommand(
    async () =>
    {
        myButton.IsEnabled = false;
        await UploadDataToDropbox("sandbox");
        myButton.IsEnabled = true;
    });

But, the disabling of the button may better done somewhere else, depending on how you're handling commands, etc... (eg if you're reusing this command for several UI tap/click events).

With an AsyncLock its possible to create a upload queue instead of simultaneous uploads:

private readonly AsyncLock _dropBoxUploadLock = new AsyncLock(); 

return _navigateToDropBoxUploadCommand = _navigateToDropBoxUploadCommand ?? new RelayCommand(
    async () =>
    {   
        var cachedStateFromUI = GetDataFromTheUI(...);
        using(var releaser = await _dropBoxUploadLock.LockAsync()) 
        {
            await UploadDataToDropbox(cachedStateFromUI);
        }
    });

The AsyncLock class used is from the example of Stephen Toub http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx

  /*
   * private readonly AsyncLock m_lock = new AsyncLock(); 
   * … 
   * using(var releaser = await m_lock.LockAsync()) 
   * { 
   *     … // protected code here 
   * }
   */

  /// <summary>
  /// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx
  /// </summary>
  public class AsyncLock
  {
    private readonly AsyncSemaphore m_semaphore;
    private readonly Task<Releaser> m_releaser;

    public AsyncLock()
    {
      m_semaphore = new AsyncSemaphore(1);
      m_releaser = Task.FromResult(new Releaser(this));
    }

    public Task<Releaser> LockAsync()
    {
      var wait = m_semaphore.WaitAsync();
      return wait.IsCompleted ?
          m_releaser :
          wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
              this, CancellationToken.None,
              TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
    }

    public struct Releaser : IDisposable
    {
      private readonly AsyncLock m_toRelease;

      internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }

      public void Dispose()
      {
        if (m_toRelease != null)
          m_toRelease.m_semaphore.Release();
      }
    } 
  }

The AsyncLock depends on the AsyncSemaphore http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx

  /*
   * private readonly AsyncSemaphore m_lock = new AsyncSemaphore(1); 
   * … 
   * await m_lock.WaitAsync(); 
   * try 
   * { 
   *     … // protected code here 
   * }  
   * finally { m_lock.Release(); }
   */

  /// <summary>
  /// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx
  /// </summary>
  public class AsyncSemaphore
  {
    private readonly static Task s_completed = Task.FromResult(true);
    private readonly Queue<TaskCompletionSource<bool>> m_waiters = new Queue<TaskCompletionSource<bool>>();
    private int m_currentCount;

    public AsyncSemaphore(int initialCount)
    {
      if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount");
      m_currentCount = initialCount;
    }

    public Task WaitAsync()
    {
      lock (m_waiters)
      {
        if (m_currentCount > 0)
        {
          --m_currentCount;
          return s_completed;
        }
        else
        {
          var waiter = new TaskCompletionSource<bool>();
          m_waiters.Enqueue(waiter);
          return waiter.Task;
        }
      }
    }

    public void Release()
    {
      TaskCompletionSource<bool> toRelease = null;
      lock (m_waiters)
      {
        if (m_waiters.Count > 0)
          toRelease = m_waiters.Dequeue();
        else
          ++m_currentCount;
      }
      if (toRelease != null)
        toRelease.SetResult(true);
    }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM