当谈到使用CAS 循环std::atomic实现时,此链接中的 cppreference给出了以下示例push:
template<typename T>
class stack
{
std::atomic<node<T>*> head;
public:
void push(const T& data)
{
node<T>* new_node = new node<T>(data);
new_node->next = head.load(std::memory_order_relaxed);
while(!head.compare_exchange_weak(new_node->next, new_node,
std::memory_order_release,
std::memory_order_relaxed /* Eh? */));
}
};
Run Code Online (Sandbox Code Playgroud)
现在,我不明白如何将 comestd::memory_order_relaxed用于失败情况,因为据我了解, (与-strongcompare_exchange_weak相同,但为了方便起见,我只是使用弱版本)是失败时的加载操作,这意味着它从另一个线程中成功的 CAS 操作加载,因此它应该使用同步…?std::memory_order_releasestd::memory_order_acquire
while(!head.compare_exchange_weak(new_node->next, new_node,
std::memory_order_release,
std::memory_order_acquire /* There you go! */));
Run Code Online (Sandbox Code Playgroud)
假设,如果“宽松负载”获得旧值之一,最终一次又一次失败,并在循环中停留额外的时间怎么办?
下面这张粗糙的图片是我的大脑被卡住的地方。
T2 的商店在 T1 上不应该可见吗?(通过相互之间具有同步关系)
总结一下我的问题,
std::memory_order_acquire,而不是std::memory_order_relaxed失败呢?std::memory_order_relaxed足够呢?std::memory_order_relaxed失败是否意味着 …当前的C++ 0x草案在第29.3.9节和第293.10节,第1111-1112节中说明,在以下示例中:
// Thread 1
r1 = y.load(memory_order_relaxed);
x.store(1, memory_order_relaxed);
// Thread 2
r2 = x.load(memory_order_relaxed);
y.store(1, memory_order_relaxed);
Run Code Online (Sandbox Code Playgroud)
结果r1 = r2 = 1是可能的,因为每个线程的操作都是放松的,并且是不相关的地址.现在我的问题是关于以下(类似)示例的可能结果:
// Thread 1
r1 = y.load(memory_order_acquire);
x.store(1, memory_order_release);
// Thread 2
r2 = x.load(memory_order_acquire);
y.store(1, memory_order_release);
Run Code Online (Sandbox Code Playgroud)
我认为在这种情况下结果r1 = r2 = 1是不可能的.如果可能的话,y的负载将与商店同步(因此发生在之前).与x类似,x的加载将在商店到x之前发生.但是y的负载在存储到x之前(因此也发生在 - 之前)被排序.这创建了一个循环发生在之前的关系,我认为是不允许的.
我有以下一些使用线程和静态变量初始化的C++ 11代码.我的问题是:
什么担保或保证,不C++语言做出静态变量的单初始化 - 下面的代码显示了正确的价值观,但我似乎无法找到在新标准中提到的内存模型应如何线程交互的通道.如果变量变为线程本地?
#include <iostream>
#include <thread>
class theclass
{
public:
theclass(const int& n)
:n_(n)
{ printf("aclass(const int& n){}\n"); }
int n() const { return n_; }
private:
int n_;
};
int operator+(const theclass& c, int n)
{
return c.n() + n;
}
void foo()
{
static theclass x = 1;
static theclass y = x + 1;
printf("%d %d\n",x.n(),y.n());
}
int main()
{
std::thread t1(&foo);
std::thread t2(&foo);
t1.join();
t2.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud) multithreading initialization static-members memory-model c++11
我对标准中的以下段落感兴趣(ISO/IEC 14882:2011(E)的 §3.9/ 4 ):
类型对象的对象表示是由类型对象占据
T的N个unsigned char对象的序列T,其中N等于sizeof(T).对象的值表示是保存type值的位集T.对于简单的可复制类型,值表示是对象表示中的一组位,用于确定值,该值是实现定义的值集的一个离散元素.42
我理解对象表示和值表示是不同的,以允许一些对象表示不参与对象的值(例如,填充).虽然我不太了解关于可复制类型的观点.非平凡的可复制类型没有值吗?非平凡可复制类型的部分值表示是否存在于其对象表示之外?
注42解释:
目的是C++的内存模型与ISO/IEC 9899编程语言C的内存模型兼容.
我仍然不明白为什么之前的声明仅适用于简单的可复制类型.这有什么意义?
众所周知,与Java的易失性不同,.NET的版本允许使用来自另一个位置的以下易失性读取来重新排序易失性写入.当它是一个问题时 MemoryBarier,建议放在它们之间,或者Interlocked.Exchange可以用来代替volatile写.
它可以工作,但MemoryBarier在高度优化的无锁代码中使用时可能成为性能杀手.
我想了一下,想出了一个主意.我希望有人告诉我,我是否采取了正确的方式.
所以,这个想法如下:
我们希望防止这两种访问之间的重新排序:
volatile1 write
volatile2 read
Run Code Online (Sandbox Code Playgroud)
从.NET MM我们知道:
1) writes to a variable cannot be reordered with a following read from
the same variable
2) no volatile accesses can be eliminated
3) no memory accesses can be reordered with a previous volatile read
Run Code Online (Sandbox Code Playgroud)
为了防止写入和读取之间不必要的重新排序,我们从刚刚写入的变量中引入了一个虚拟易失性读取:
A) volatile1 write
B) volatile1 read [to a visible (accessible | potentially shared) location]
C) volatile2 read
Run Code Online (Sandbox Code Playgroud)
在这种情况下,B不能用A重新排序,因为它们都访问相同的变量, C不能用B重新排序,因为两个易失性读取不能相互重新排序,并且传递C …
基本上我无法理解这一点:(来自Bjarne FAQ)
但是,大多数现代处理器不能读取或写入单个字符,它必须读取或写入整个单词,因此对c的赋值实际上是"读取包含c的单词,替换c部分,然后再将单词写回". '由于对b的赋值是相似的,所以即使线程没有(根据它们的源文本)共享数据,两个线程也有很多机会相互冲突!
那么char数组如何在元素之间没有3(7?)字节填充的情况下存在?
我在x64上测试了c ++ 11内存模型的轻松排序语义,我被告知在x86/64上只存在存储/加载重新排序,所以我编写了以下程序来测试轻松排序.
理想情况下,如果存在重新排序(它确实存在),那么我的程序应该达到"g_a == g_b == 0"的情况,但我测试了很长时间,并且从未得到预期的结果,任何人都可以帮忙解释一下为什么?谢谢.
[更新]
抱歉忘记提及我使用的编译器,在Linux x86/64上使用g ++ 4.8.3编译时,以下代码将无法正常工作.感谢@Mat的提醒,然后我尝试使用clang ++ 3.4.2编译它,这次我看到了重新排序,所以它可能是g ++中的一个错误.
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
atomic<int> g_a, g_b;
atomic<int> g_x, g_y;
memory_order order = memory_order_relaxed;
void bar1()
{
register int t = 0;
g_x.store(42, order);
t = g_y.load(order);
g_a = t;
}
void bar2()
{
register int t = 0;
g_y.store(24, order);
t = g_x.load(order);
g_b = t;
}
int main()
{
for (int i = 0; i < 1000000; …Run Code Online (Sandbox Code Playgroud) Java的内存模型基于强制执行规则的“先有先后”关系,但也允许在缓存失效方面优化虚拟机的实现。
例如,在以下情况下:
// thread A
private void method() {
//code before lock
synchronized (lockA) {
//code inside
}
}
// thread B
private void method2() {
//code before lock
synchronized (lockA) {
//code inside
}
}
// thread B
private void method3() {
//code before lock
synchronized (lockB) {
//code inside
}
}
Run Code Online (Sandbox Code Playgroud)
如果线程A调用method()而线程B试图在lockA内部获取method2(),则同步lockA将要求线程B在释放其锁之前,观察线程A对所有变量所做的所有更改,甚至包括之前在“代码”中更改的变量。锁定”部分。
另一方面,method3()使用另一个锁并且不强制发生关系之前的事件。这为优化创造了机会。
我的问题是虚拟机如何实现那些复杂的语义?是否在不需要缓存时避免完全刷新缓存?
它如何跟踪在哪个点哪个线程更改了哪个变量,从而仅从内存加载所需的缓存行?
multithreading jvm memory-model happens-before vm-implementation
如何在ruby中管理内存.对于Ex:如果我们在执行期间采用C程序,则以下是内存模型.与此类似,如何在ruby中处理内存.
C:
__________________
| |
| stack |
| |
------------------
| |
| <Un Allocated|
| space> |
------------------
| |
| |
| Heap |
| |
| |
__________________
| |
| data |
__________________
| text |
__________________
Ruby:
?
Run Code Online (Sandbox Code Playgroud) 我一直在研究原子引用计数的实现。
大多数操作在库之间是非常一致的,但是我发现“减少引用计数”操作令人吃惊。(请注意,通常,共享和弱decref之间的唯一区别是on_zero()被调用。下面将说明异常。)
如果还有其他根据C11 / C ++ 11模型实现的实现(MSVC做了什么?),而不是“我们使用seq_cst,因为我们没有更好的了解”类型,请随时对其进行编辑。
大多数示例最初都是C ++,但是在这里,我将它们重写为C,内联并按照>= 1约定进行了规范化:
#include <stdatomic.h>
#include <stddef.h>
typedef struct RefPtr RefPtr;
struct RefPtr {
_Atomic(size_t) refcount;
};
// calls the destructor and/or calls free
// on a shared_ptr, this also calls decref on the implicit weak_ptr
void on_zero(RefPtr *);
Run Code Online (Sandbox Code Playgroud)
从Boost intrusive_ptr示例和openssl:
void decref_boost_intrusive_docs(RefPtr *p) {
if (atomic_fetch_sub_explicit(&p->refcount, 1, memory_order_release) == 1) {
atomic_thread_fence(memory_order_acquire);
on_zero(p);
}
}
Run Code Online (Sandbox Code Playgroud)
可以对fetch_sub操作使用memory_order_acq_rel,但是当引用计数器尚未达到零时,这会导致不必要的“获取”操作,并且可能会导致性能下降。
但大多数其他工具( Boost, libstdc ++, libc ++ …