我当前正在制作一个具有多个并行运行的工作线程的应用程序。该程序的主要部分在工作人员之前执行,每个工作人员完成任务后都进入睡眠状态:
MainLoop()
{
// ...
SoundManager::PlaySound("sound1.mp3"); // Add a sound to be played, store the sound in a list in SoundManager
SoundManager::PlaySound("sound2.mp3");
SoundManager::PlaySound("sound3.mp3");
// ...
SoundThreadWorker.RunJob(); // Wake up thread and play every sound pushed in SoundManager
// Running other threads
SoundThreadWorker.WaitForFinish(); // Wait until the thread have finished its tasks, thread is put to sleep(but not closed)
// Waiting other threads
// ...
}
// In SoundThreadWorker class, running in a different thread from the main loop
RunJob()
{
SoundManager::PlayAllSound(); // Play all sound stored in SoundManager
}
在这种情况下,存储所有声音的静态变量应该是安全的,因为在线程运行时不会添加声音。
此缓存有效吗?
我在这里读到了https://www.agner.org/optimize/optimizing_cpp.pdf
“不同的线程需要单独存储。没有函数或类 多线程使用的线程应依赖静态或全局 变量。 (请参阅第28页的线程本地存储)线程具有 他们的堆栈。如果线程共享,这可能导致缓存争用 相同的缓存。”
我很难理解静态变量如何存储在缓存中以及每个线程如何使用它们。由于线程不共享堆栈,因此我在缓存中是否有两个SoundManager实例?我需要创建共享内存来避免此问题吗?
答案 0 :(得分:2)
这段话是关于改变的记忆,而不是关于保持不变的记忆。在线程之间共享常量很好。
当有多个CPU每个都在更新同一个地方时,它们必须一直来回相互发送更改。这导致争用“拥有”一块特定的内存。
通常所有权不是明确的。但是,当一个CPU告诉所有其他CPU某个特定的高速缓存行因为刚刚更改了那里的内容而需要使之无效时,则所有其他CPU必须从其高速缓存中逐出该值。这会导致CPU最后修改一块内存,从而有效地“拥有”它所在的缓存行。
同样,这仅是已更改事物的问题。
此外,我为您提供的内存和缓存视图非常简单。在推理特定代码的线程安全性时,请不要使用它。足以理解为什么多个CPU更新同一块内存对您的缓存不利,但不足以了解特定内存位置的哪个CPU版本最终被其他CPU使用。
在一个线程被多个线程使用的生命周期内不变的内存位置将导致该内存位置出现在多个CPU缓存中。但这不是问题。对于一个不变的特定内存位置来说,存储在CPU之间共享的L2和L3缓存中也不是问题。