考虑以下简单函数(假设大多数编译器优化关闭)由具有存储缓冲区的 X86 CPU 上不同内核上的两个线程执行:
struct ABC
{
int x;
//other members.
};
void dummy(int index)
{
while(true)
{
auto abc = new ABC;
abc->x = index;
cout << abc->x;
// do some other things.
delete abc;
}
}
Run Code Online (Sandbox Code Playgroud)
这里,index是线程的索引;1 由线程1 传递,2 由线程2 传递。因此,线程 1 应该始终打印 1,线程 2 应该始终打印 2。
是否存在这样的情况,即存储到x被放入存储缓冲区并在执行delete之后提交?或者是否存在隐式内存屏障来确保在删除之前提交存储?或者一旦遇到删除,任何未完成的存储都会被丢弃?
这变得很重要的情况:
由于delete是将对象的内存返回到空闲列表中(用libc),因此有可能在thread1中刚刚释放的一块内存被thread2中的new操作符返回(不仅是虚拟地址,甚至是返回的底层物理地址可以是相同的)。如果未完成的存储可以在删除后执行,则线程 2 将 abc->x 设置为 2 后,线程 1 中的某些较旧的未完成存储可能会将其覆盖为 1。
这意味着在上面的程序中,thread2可以打印1,这是绝对错误的。线程1和线程2是完全独立的,从程序员的角度来看,线程之间没有数据共享,并且它们不必担心任何同步。
我在这里缺少什么?