【发布时间】:2021-06-24 22:29:10
【问题描述】:
下一刻有人可以澄清一下。我看到了一些用于多线程目的的 std::queue 实现,其中推/弹出/擦除元素的所有操作都受互斥锁保护,但是当我看到我想象下一个场景时:我们有两个线程(线程 1 和线程 2),它们是在处理器的不同内核上运行,因此它们具有不同的 L1 缓存。我们有下一个队列:
struct Message {
char* buf;
size_t size;
};
std::queue<Message> messageQueue;
Thread1 将一些元素添加到队列中,然后 thread2 尝试使用 front() 方法访问一个元素,但是如果该内存块预先为处理器的这个核心缓存了怎么办(因此 size 变量可能不表示当前的大小buf 变量或 buf 指针可能持有错误(未更新)的地址)? 我在服务器端设计客户端/服务器应用程序时遇到了这样的问题。在我的应用程序服务器中运行在一个线程中,它直接与套接字一起工作,当它接收到新消息时,它为该消息分配内存并将该消息添加到某个消息队列中,然后其他线程访问该队列,处理消息然后删除它。我总是害怕缓存问题,因此我创建了自己的带有可变指针的队列实现。 处理这些事情的正确方法是什么?我必须避免使用带锁的 std::list、std::queue 吗?如果这个问题是不可能的,你能解释一下原因吗?
【问题讨论】:
-
“处理此类事情的正确方法”是使用互斥体,它将正确处理所有排序。
volatile对象在这里没有任何用处。volatile的唯一含义是任何对它的引用都不会被优化。它不保证对对象的任何更改都会立即同步到所有其他执行线程。 -
我确实相信 volatile 还可以防止缓存(变量每次使用时都会从内存中读取)。但我同意这不足以正确同步stackoverflow.com/questions/18695120/…。
-
但是如果我锁定了一些互斥体,我怎么能确定这个内存没有被缓存,或者互斥体锁定以某种方式保证直接从内存中读取?
-
C++ 标准要求在修改操作观察到由该修改操作写入的值(或可能在其间发生的一些其他操作)之后发生正确同步的读取操作。这是如何实现的,是一个内部实现细节。 CPU 提供允许编译器提供适当实现的机器指令(栅栏、内存屏障)。
-
使用互斥锁比
volaltile需要花费数周时间调试的错误快得多。
标签: c++ multithreading caching