同步对象是不是可缓存?
Posted
技术标签:
【中文标题】同步对象是不是可缓存?【英文标题】:Are synchronization objects cacheable?同步对象是否可缓存? 【发布时间】:2011-07-07 03:42:12 【问题描述】:我是多线程世界的新手,并开始涉足它。我发现线程需要同步。易失性不再是可靠的东西。我想知道同步对象是否可以被编译器缓存或在任何阶段缓存?
使用的平台/语言:c++、win32、Windows
在 c++ 中,volatile 关键字用于 CPU 无法缓存的对象。但是今天的编译器并没有严格遵循这一点。是否有其他方法可以使同步对象不可缓存(或其他优化不适用于这些对象)。
tl;dr:同步对象可以缓存吗?如果是,如何使其不可缓存?
【问题讨论】:
真的很难理解你在问什么:这个问题有点含糊不清。您对同步对象有什么顾虑:即您担心它会发生什么? 如果同步对象被缓存在多个 CPU 上并且没有更新到内存。会发生这种情况吗? 当然,同步对象可能会被缓存,但这对同步块的影响很小。只要对对象的实际引用没有改变(即你没有让它指向不同的对象),那么你就不用担心了。 如果一个 CPU 更新内存而另一个没有更新新值怎么办?它会发生吗?或者内存的变化也会更新 CPU 缓存? 只要你不改变你的对象指向的东西,你对那个对象做了什么并不重要。 【参考方案1】:我不确定我是否遵循您的问题:编译器缓存几乎与多线程无关。编译器缓存唯一能做的就是通过缓存以前的编译来提高编译速度。
同步对象可以被“缓存”,因为它们是您决定用于同步的任意对象,但这对并发性影响不大。同步时唯一需要注意的是,当您有多个线程争用资源时,它们必须都在同一个对象上同步才能获得对资源的读/写访问权限。
根据您提到的易失性,我将进行一个大胆的猜测,并假设您担心同步对象可能会缓存在线程的本地缓存中,并且可能不会从一个线程对同步对象进行更改对另一个线程可见。然而,这是一个有缺陷的想法:
-
当您调用 lock() 或 synchronize()(取决于语言)时,您只需要关心锁定是在同一个对象上执行的,而不管对象的内部状态如何。
在对象上获得锁后,您在该锁范围内修改的任何资源都将仅由一个线程修改。
通常,您应该使用不会改变的同步对象(理想情况下是只读的、常量或最终的),我们在这里只讨论引用,而不是对象本身的内容。这是一个例子:
对象同步 = 新对象(); 字符串某事=“你好”:
void ModifySomething() sync = new object();//
现在请注意,每次线程调用ModifySomething
,同步对象都会被一个新对象替换,并且线程永远不会在同一个对象上同步,因此可能会有并发写入something
。
【讨论】:
如果有多个 CPU,缓存可能是敌人。有没有办法让它不可缓存(在 c++ 中 volatile 似乎有编译器依赖的限制)【参考方案2】:如果不指定运行时环境,这个问题就没有多大意义。
在 Java 的例子中,同步对象(用于同步的对象)就像任何其他对象一样。 对象是同步的目标,所以volatile
(适用于成员变量)只有在变量包含同步对象时才需要可以换。我会避免需要这种结构的程序设计。
请记住(同样,在 Java 中),正是表达式的求值——通常是变量访问——导致要使用的同步对象。本次评估在这方面与其他评估没有什么不同。
然而,归根结底,它只是以定义明确且行为良好的方式使用特定运行时/环境的同步工具。
编码愉快。
例如,Java 保证 synchronized(x) foo
(其中 x 是一个特定对象)将创建一个互斥的临界区,在该临界区中执行 foo
。为此,它必须进行内部工作以确保簿记数据在所有处理器/缓存中正确刷新。但是,就使用同步构造而言,这些细节通常超出了运行时的范围。
【讨论】:
@Hem 更新原始问题。另外,pthreads使用什么形式的同步?其他?请明确点。归根结底,唯一的后果是库的保证语义......(也可能需要考虑强/弱内存模型)。【参考方案3】:同步对象必须由操作系统管理,操作系统也管理线程和缓存。因此,处理缓存是操作系统的责任。如果它以某种方式知道同步对象仅在单个 CPU 上使用(例如,因为它没有为您的进程分配第二个 CPU),操作系统很可能决定将同步对象保留在第一个 CPU 的缓存中。如果它需要在 CPU 之间共享,那么也会发生这种情况。
一个实际的结果是您将始终初始化同步对象。在 C++ 中,这是很自然的(构造函数负责处理),但在其他语言中,您必须明确地这样做。操作系统必须跟踪同步对象。
【讨论】:
以上是关于同步对象是不是可缓存?的主要内容,如果未能解决你的问题,请参考以下文章
text 从ISO *创建可启动的usb密钥,同时复制*同步(缓存中不再有数据)。