async 和 await 是否产生获取和释放语义?

Do async and await produce acquire and release semantics?

关于从 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 还需要生成一个版本,并且在开始 运行 任务代码时需要一个获取。忘记了原始问题中的那些。

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

在这种情况下,是 Task.Run 而不是 await 产生了内存屏障。

引用wonderful Albahari Threading in C#

The following implicitly generate full fences:

  • C#'s lock statement (Monitor.Enter/Monitor.Exit)
  • All methods on the Interlocked class (we’ll cover these soon)
  • Asynchronous callbacks that use the thread pool — these include asynchronous delegates, APM callbacks, and Task continuations
  • Setting and waiting on a signaling construct
  • Anything that relies on signaling, such as starting or waiting on a Task

By virtue of that last point, the following is thread-safe:

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

Task.Run 包装 ThreadPool.UnsafeQueueUserWorkItem,属于“使用线程池的异步回调”。

请参阅 Memory barrier generators 以获取更全面的内存障碍列表。