C++ 11引入了标准化的内存模型,但究竟是什么意思呢?它将如何影响C++编程?
这篇文章(引用Herb Sutter的Gavin Clarke)说,
内存模型意味着C++代码现在有一个标准化的库可以调用,无论是谁编译器以及它运行的平台.有一种标准方法可以控制不同线程与处理器内存的对话方式.
"当你谈论在标准中的不同内核之间分割[代码]时,我们正在谈论内存模型.我们将优化它,而不会破坏人们将在代码中做出的以下假设," Sutter说.
好吧,我可以在网上记住这个和类似的段落(因为我从出生以来就拥有自己的记忆模型:P),甚至可以发布作为其他人提出的问题的答案,但说实话,我并不完全明白这个.
C++程序员以前用于开发多线程应用程序,那么如果它是POSIX线程,Windows线程或C++ 11线程,它又如何重要呢?有什么好处?我想了解低级细节.
我也觉得C++ 11内存模型与C++ 11多线程支持有某种关系,因为我经常将这两者结合在一起.如果是,究竟是怎么回事?他们为什么要相关?
由于我不知道多线程的内部工作原理以及内存模型的含义,请帮助我理解这些概念.:-)
我熟悉Java中许多围绕并发的机制和习惯用法.我困惑的地方是一个简单的概念:同一对象的不同成员的并发访问.
我有一组可由两个线程访问的变量,在这种情况下涉及游戏引擎中的图形信息.我需要能够在一个线程中修改对象的位置并在另一个线程中读取它.解决此问题的标准方法是编写以下代码:
private int xpos;
private object xposAccess;
public int getXpos() {
int result;
synchronized (xposAccess) {
result = xpos;
}
return result;
}
public void setXpos(int xpos) {
synchronized (xposAccess) {
this.xpos = xpos;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我正在编写一个实时游戏引擎,而不是一个20个问题的应用程序.我需要快速工作,特别是当我访问和修改它们时,就像我处理图形资产的位置一样.我想删除同步开销.更好的是,我想完全删除函数调用开销.
private int xpos;
private int bufxpos;
...
public void finalize()
{
bufxpos = xpos;
...
}
Run Code Online (Sandbox Code Playgroud)
使用锁,我可以使线程彼此等待,然后调用finalize(),同时既不访问也不修改对象.在这个快速缓冲步骤之后,两个线程都可以自由地操作对象,一个修改/访问xpos,一个访问bufxpos.
我已经成功地使用了类似的方法,其中信息被复制到第二个对象,并且每个线程作用于单独的对象.但是,两个成员仍然是上述代码中同一个对象的一部分,当我的线程同时访问对象时,即使在对不同的成员进行操作时,也会发生一些有趣的事情.不可预知的行为,幻像图形对象,屏幕位置的随机错误等.为了验证这确实是一个并发问题,我在一个线程中运行了两个线程的代码,在那里它执行完美.
我希望性能高于一切,我正在考虑缓存关键数据以分离对象.我的错误是由并发访问相同对象引起的吗?是否有更好的并发解决方案?
编辑:如果你怀疑我的表现估价,我应该给你更多的背景.我的引擎是为Android编写的,我使用它来绘制数百或数千个图形资源.我有一个单线程解决方案,但是自从实现多线程解决方案以来,我看到性能几乎翻了一番,尽管存在幻像并发问题和偶尔的未捕获异常.
编辑:感谢关于多线程性能的精彩讨论.最后,我能够通过在工作线程处于休眠状态时缓冲数据来解决问题,然后允许它们在对象内的每个数据集进行操作.
在此处的oracle Java文档中,如下所示:
原子动作不能交错,因此可以使用它们而不必担心线程干扰.但是,这并不能消除所有同步原子操作的需要,因为仍然可能存在内存一致性错误.使用volatile变量可降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系.这意味着对volatile变量的更改始终对其他线程可见.更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用.
它还说:
关于这些陈述,我有两个问题:
"使用volatile变量降低了内存一致性错误的风险" - 它们的意思是"降低风险",以及在使用volatile时如何仍然可以实现内存一致性错误?
如果将volatile放在非双非长基元上的唯一效果是,是否能够与其他线程的后续读取启用"先发生"关系?我问这个,因为这些变量似乎已经有了原子读数.