Can a Task have multiple awaiters?

前端 未结 2 719
一整个雨季
一整个雨季 2020-12-19 02:29

I am toying around with an async service for a Windows 8 project and there are some async calls of this service, which should only be called once at a time.



        
2条回答
  •  鱼传尺愫
    2020-12-19 02:55

    A task can have multiple awaiters. However, as Damien pointed out, there's serious race conditions with your proposed code.

    If you want the code executed each time your method is called (but not simultaneously), then use AsyncLock. If you want the code executed only once, then use AsyncLazy.

    Your proposed solution attempts to combine multiple calls, executing the code again if it is not already running. This is more tricky, and the solution heavily depends on the exact semantics you need. Here's one option:

    private AsyncLock mutex = new AsyncLock();
    private Task executing;
    
    public async Task CallThisOnlyOnceAsync()
    {
      Task action = null;
      using (await mutex.LockAsync())
      {
        if (executing == null)
          executing = DoCallThisOnlyOnceAsync();
        action = executing;
      }
    
      await action;
    }
    
    private async Task DoCallThisOnlyOnceAsync()
    {
      PropagateSomeEvents();
    
      await SomeOtherMethod();
    
      PropagateDifferentEvents();
    
      using (await mutex.LockAsync())
      {
        executing = null;
      }
    }
    

    It's also possible to do this with Interlocked, but that code gets ugly.

    P.S. I have AsyncLock, AsyncLazy, and other async-ready primitives in my AsyncEx library.

提交回复
热议问题