async 和 await 是否产生获取和释放语义?
Do async and await produce acquire and release semantics?
关于从 async
方法返回是否总是产生释放语义以及 await
是否总是产生获取语义,我找不到明确的答案。我想是的,因为否则任何 async/await
代码都会成为雷区?
下面是一个示例:返回值是否保证为 100*2
和 12345*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*2
和 12345*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 以获取更全面的内存障碍列表。
关于从 async
方法返回是否总是产生释放语义以及 await
是否总是产生获取语义,我找不到明确的答案。我想是的,因为否则任何 async/await
代码都会成为雷区?
下面是一个示例:返回值是否保证为 100*2
和 12345*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*2
和 12345*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 以获取更全面的内存障碍列表。