- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在阅读有关 DCLP(双重检查锁定模式)的信息,但我不确定自己是否理解正确。当使用原子创建锁时(如 DCLP fixed in C++11 中所述),有两件事不清楚:
std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
Singleton* tmp = m_instance.load(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_relaxed);
if (tmp == nullptr) {
tmp = new Singleton;
m_instance.store(tmp, std::memory_order_release);
}
}
return tmp;
}
如果我在“load()”中获取栅栏,但 tmp 不是 nullptr,我只是返回,会发生什么?我们不应该说明 CPU 可以在哪里“释放围栏”吗?
如果不需要释放围栏,那我们为什么要获取和释放?有什么区别?
很遗憾,我遗漏了一些基本的东西......
Singleton* Singleton::m_instance = null;
std::atomic<bool> Singleton::is_first; // init to false
std::mutex Singleton::m_mutex;
Singleton* Singleton::getInstance() {
bool tmp = is_first.load(std::memory_order_acquire);
if (tmp == false) {
std::lock_guard<std::mutex> lock(m_mutex);
tmp = is_first.load(std::memory_order_relaxed);
if (tmp == false) {
// can place any code that will run exactly once!
m_instance = new Singleton;
// store back the tmp atomically
is_first.store(tmp, std::memory_order_release);
}
}
return m_instance;
}
换句话说,我没有查看实例,而是使用原子 bool 值来确保 DCLP 正常工作,并且第二个 tmp 中的任何内容都将被同步并运行一次。是否正确?
谢谢!
编辑:请注意,我不是在问实现单例的问题,而只是为了更好地理解 fences 和 atomic 的概念以及它如何修复 DCLP。这是一个理论问题。
最佳答案
What happens if I aquire the fence inside "load()", but than tmp is not nullptr, and I simply return? Shouldn't we state where the CPU can "release the fence"?
没有。当商店进入 m_instance
时发布完成发生。如果加载 m_instance
并且它不为空,那么发布已经发生在更早的时候,你不需要这样做。
您不会像获得互斥锁那样“获得栅栏”和“释放栅栏”。栅栏不是这样的。栅栏只是一个没有关联内存位置的获取或释放操作。栅栏在这里并不真正相关,因为所有获取和释放操作都有一个关联的内存位置(原子对象 m_instance
)。
您不必像互斥锁+解锁那样成对地获取+释放。您可以执行一个释放操作来存储一个值,并进行任意数量的获取操作(零个或多个)来加载该值并观察其效果。
加载/存储上的获取/释放语义与加载/存储两侧的操作排序相关,以防止重新排序。
对变量 A 的非松弛原子存储(即释放操作)将与同一变量 A 的稍后非松弛原子加载(即获取操作)同步。
正如 C++ 标准所说:
Informally, performing a release operation on A forces prior side effects on other memory locations to become visible to other threads that later perform a consume or an acquire operation on A.
因此在您引用的 DCLP 代码中,m_instance.store(tmp, memory_order_release)
是m_instance
的商店并且是释放操作。 m_instance.load(memory_order_acquire)
是来自 m_instance
的负载并且是一个获取操作。内存模型表示,非空指针的存储与任何看到非空指针的加载同步,这意味着可以保证 new Singleton
的所有效果。在任何线程可以从 tmp
加载非空值之前已经完成.这修复了 C++11 之前的双重检查锁定存储到 tmp
的问题。在对象完全构造之前,其他线程可以看到它。
In other words, instead of looking at the instance I am using an atomic boolean to make sure the DCLP works, and whatever is inside the second tmp is surly to be syncronized and run once. Is it correct?
不,因为你存储了false
这里:
// store back the tmp atomically
is_first.store(tmp, std::memory_order_release);
这意味着在下次调用该函数时,您将创建另一个 Singleton
并泄漏第一个。应该是:
is_first.store(true, std::memory_order_release);
如果你解决了这个问题,我认为它是正确的,但在典型的实现中它使用更多的内存( sizeof(atomic<bool>)+sizeof(Singleton*)
可能比 sizeof(atomic<Singleton*>)
多),并且通过将逻辑分成两个变量(一个 bool 值和一个指针)你像你一样更容易犯错。因此,与原始方式相比,这样做没有任何优势,在原始方式中,指针本身也用作 bool 值,因为您直接查看指针,而不是某些可能未正确设置的 bool 值。
关于c++ - C++11 中双重检查锁定模式 (DCLP) 的实现是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30587666/
我正在阅读解释 DCLP 中问题的文章“C++ and the Perils of Double-Checked Locking”。 文章的第二部分(链接转发的地方)展示了如何尝试仅使用 C/C++
我正在阅读有关 DCLP(双重检查锁定模式)的信息,但我不确定自己是否理解正确。当使用原子创建锁时(如 DCLP fixed in C++11 中所述),有两件事不清楚: 文章中的代码: std::a
假设我们有以下(伪)代码: using UpgradeLock = boost::upgrade_lock; using UpgradeToUniqueLock = boost::upgrade_to
我是一名优秀的程序员,十分优秀!