我是多线程世界的新手,并开始涉足它。我发现线程需要同步。挥发性不再是可靠的东西。我想知道同步对象是否可以被编译器或任何阶段缓存?
使用的平台/语言:c ++,win32,Windows
在c ++中,volatile关键字用于CPU无法缓存的对象。但今天的编译器并没有严格遵循这一点。是否还有其他方法可以使同步对象不可缓存(或者不对这些对象应用其他优化)。
tl; dr:同步对象是否可缓存?如果是,你怎么能让它不可缓存?
答案 0 :(得分:1)
我不确定我是否遵循了您的问题:编译器缓存几乎与多线程无关。编译器缓存唯一能做的就是通过缓存以前的编译来提高编译速度。
同步对象可以被高速缓存"因为它们是您决定用于同步的任意对象,但这对并发性几乎没有影响。在同步时,您唯一需要关心的是当您有多个线程争用资源时,它们必须在同一个对象上进行同步才能获得对资源的读/写访问权限。
我会根据你提到的volatile来猜测,并假设你担心同步对象可能被缓存在一个线程的本地缓存中并且更改为来自一个线程的同步对象可能对另一个线程不可见。然而,这是一个有缺陷的想法:
通常,你应该使用一个不会改变的同步对象(理想情况下是readonly,const或final),我们只讨论这里的引用,而不是对象本身的内容。这是一个例子:
object sync = new object(); string something ="你好":
void ModifySomething()
{
sync = new object(); //< - 你永远不应该这样做!!
锁(同步)
{
something = GenerateRandomString();
}
}
现在请注意,每次线程调用ModifySomething
时,同步对象都将被新对象替换,并且线程将永远不会在同一对象上同步,因此可能会有something
的并发写入
答案 1 :(得分:0)
如果没有指定运行时环境,这个问题没有多大意义。
例如,Java ,例如,同步对象(用于同步的对象)就像任何其他对象一样。 对象是同步的目标,因此只有在包含同步对象的变量时才需要volatile
(适用于成员变量)可以改变。我会避免需要这种结构的程序设计。
记住(再次,在Java中),表达式的评估 - 通常是变量访问 - 导致同步对象使用。此评估与此方面的任何其他评估没有什么不同。
然而,在一天结束时,它只是使用特定运行时/环境的同步工具,其方式是定义良好且行为良好。< / p>
快乐的编码。
synchronized(x) { foo }
(其中x是特定对象)将创建一个互斥的关键区域,其中foo
被执行。为此,必须执行内部工作以确保在所有处理器/缓存中正确刷新簿记数据。但是,就使用同步构造而言,这些细节通常超出了运行时的范围。
答案 2 :(得分:0)
同步对象必须由操作系统管理,操作系统还管理线程和缓存。因此,操作系统负责处理缓存。如果它以某种方式知道同步对象仅在单个CPU上使用(例如,因为它没有将第二个CPU分配给您的进程),操作系统可能会很好地决定将同步对象保留在第一个CPU中#39 ; s缓存。如果它需要在CPU之间共享,那么这也会发生。
一个实际结果是您始终初始化同步对象。在C ++中,这是自然的(构造函数会处理它),但在其他语言中,您必须明确地这样做。操作系统必须跟踪同步对象。