我在阅读这篇关于无锁线程同步的MSDN文章。该文章似乎暗示着只要在访问共享变量之前进入锁定状态,那么这些变量将是最新的(至少在.Net2.0中)。
我开始思考这是如何可能的?在.Net中,锁仅是一些任意对象,所有线程在访问内存之前都会检查它,但锁本身并不知道正在访问的内存位置。
如果有一个线程更新变量,甚至是整个内存块,当进入/退出锁定状态时,如何保证这些更新被刷新出CPU缓存?所有内存访问是否在锁定期间有效地变为易失性?
我在阅读这篇关于无锁线程同步的MSDN文章。该文章似乎暗示着只要在访问共享变量之前进入锁定状态,那么这些变量将是最新的(至少在.Net2.0中)。
我开始思考这是如何可能的?在.Net中,锁仅是一些任意对象,所有线程在访问内存之前都会检查它,但锁本身并不知道正在访问的内存位置。
如果有一个线程更新变量,甚至是整个内存块,当进入/退出锁定状态时,如何保证这些更新被刷新出CPU缓存?所有内存访问是否在锁定期间有效地变为易失性?
查看Eric Lippert的工作:http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx
锁定确保在锁定内读取或修改的内存被观察为一致性,锁定确保每次只有一个线程访问给定的内存块等。
因此,只要在访问共享资源之前每次都锁定,您就可以相当肯定地知道它是最新的。
编辑 查阅以下帖子以获取更多信息和非常有用的概述:http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/
好的,这篇文章解释了:
读取操作不能在进入锁之前移动。
写入操作不能在退出锁之后移动。
同一篇文章中还有更多的解释:
当一个线程退出锁时,第三条规则确保在持有锁期间进行的任何写操作对所有处理器都可见。在另一个线程访问内存之前,读取线程将进入锁定状态,并且第二条规则确保读取操作在获取锁之后逻辑上发生。
我不确定.NET的情况,但在Java中,明确规定任何以这种方式合作的两个线程必须使用相同的对象进行锁定,才能从您在介绍语句中所说的内容中受益,而不仅仅是任何锁。这是一个关键的区别。
锁定不需要“知道”它保护什么;它只需要确保前一个锁定器编写的所有内容在让其继续之前都可以被另一个锁定器使用。