异步并等待产生获取和释放语义吗?

时间:2019-03-13 09:43:41

标签: c# .net async-await language-lawyer memory-model

对于从async方法返回是否总是产生释放语义以及await是否总是产生获取语义,我找不到明确的答案。我假设是的,因为否则任何async/await代码都将是一个雷区?

所以这是一个例子:返回值是否保证为100*212345*2,而没有任何显式的锁或障碍?

private static async Task<(int, int)> AMethod()
{
    // Runs on the original thread:
    var x = 100;
    var y = 12345;

    var task = Task.Run(() =>
    {
        // Can run on another thread:
        x *= 2;
        y *= 2;

        // Implicit return here, marking the task completed.
        // Release semantics or not?
    });

    await task; // Acquire semantics or not?

    // Runs on the original thread:
    return (x, y);
}

编辑:当然,Task.Run还需要产生一个发行版,并且在开始运行任务的代码时需要一个获取。忘记了原始问题中的内容。

1 个答案:

答案 0 :(得分:3)

是的,保证返回的值都是100*212345*2,没有任何显式的锁或障碍。

在这种情况下,产生内存障碍的是Task.Run,而不是await

引用wonderful Albahari Threading in C#

  

以下隐式生成完整的篱笆:

     
      
  • C#的lock语句(Monitor.Enter / Monitor.Exit)
  •   
  • Interlocked类上的所有方法(我们将在后面介绍)
  •   
  • 使用线程池的异步回调-其中包括异步委托,APM回调和任务延续
  •   
  • 设置并等待信令构造
  •   
  • 任何与信号有关的东西,例如启动或等待任务
  •   
     

凭借最后一点,以下内容是线程安全的:

int x = 0;
Task t = Task.Factory.StartNew (() => x++);
t.Wait();
Console.WriteLine (x);    // 1

Task.Run包装ThreadPool.UnsafeQueueUserWorkItem,该文本位于“使用线程池的异步回调”下。

请参阅Memory barrier generators,以获得构成内存障碍的更全面的信息。