对于从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
还需要产生一个发行版,并且在开始运行任务的代码时需要一个获取。忘记了原始问题中的内容。
答案 0 :(得分:3)
是的,保证返回的值都是100*2
和12345*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,以获得构成内存障碍的更全面的信息。