异步/等待线程安全与内存缓存
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步/等待线程安全与内存缓存相关的知识,希望对你有一定的参考价值。
我正在查看http://www.albahari.com/threading/part4.aspx中描述的关于内存屏障的部分,并尝试制作“我们真的需要锁和障碍吗?”下提供的示例的异步/等待版本:
public class Program
static void Main(string[] args)
TestAsync();
Console.ReadKey(true);
private static async void TestAsync()
bool complete = false;
Func<Task> testFunc = async () =>
await Task.Delay(1000);
bool toggle = false;
while (!complete) toggle = !toggle;
;
var task = testFunc();
Thread.Sleep(2000);
complete = true;
await task;
Console.WriteLine("Done");
在没有调试的情况下在释放模式下运行时,程序将永远不会按照它基于的原始线程示例完成。
但是,由于上下文保存的方式,我在async / await的印象下会阻止这些问题。或者在使用async / await时是否仍然适用所有线程安全规则?
这实际上是一个编译优化问题。当您在发布中编译时出于某种原因,它预测完成将永远不会是真的并无限运行您的应用程序。既然你是基于另一个例子,我猜你已经知道了。但就async / await而言,它不能归咎于它。
要完成这项工作,您仍然需要将complete设置为volatile变量,如下所示:
static volatile bool complete = false;
这将告诉编译器每个周期检查它,无论它是否有效。
我不是说我同意它,但正在发生的事情是编译器看到完全没有变化直到while(!complete)部分,并且因为没有volatile关键字它决定它永远不会改变为优化性能。
另一种使这项工作的方法是删除编译器优化。您可以单击项目“属性”,然后单击“构建”选项卡,并取消选中“优化代码”。然后它将在发布中工作。
问题是访问complete
变量不同步。 await
将在任务运行之前和之后插入障碍,以确保任务延续看到新值,但请注意,在此示例中,这将无济于事。在complete = true
之后,等待任务的事实并没有插入障碍,无论如何,循环线程也没有同步读取变量。
允许编译器优化代码,但即使没有,代码也可能在实践中永远运行,因为complete
变量的值永远不会在两个线程之间显式可见。
这可以通过同步方法来解决,比如'volatile'。
以上是关于异步/等待线程安全与内存缓存的主要内容,如果未能解决你的问题,请参考以下文章