诚然,我不明白.假设您的内存中包含长度为1个字节的内存字.为什么不能在未对齐地址的单个内存访问中访问一个4字节长的变量(即不能被4整除),因为对齐地址就是这种情况?
一般地,对于int num,num++(或++num),作为读-修改-写操作中,是不是原子.但我经常看到编译器,例如GCC,为它生成以下代码(在这里尝试):
由于第5行对应于num++一条指令,我们可以得出结论,在这种情况下num++ 是原子的吗?
如果是这样,是否意味着如此生成num++可以在并发(多线程)场景中使用而没有任何数据争用的危险(例如,我们不需要制作它,std::atomic<int>并强加相关成本,因为它是无论如何原子)?
UPDATE
请注意,这个问题不是增量是否是原子的(它不是,而且是问题的开头行).它是否可以在特定场景中,即在某些情况下是否可以利用单指令性质来避免lock前缀的开销.而且,作为公认的答案约单处理器的机器,还有部分提到这个答案,在其评论和其他人谈话解释,它可以(尽管不是C或C++).
在C++中,
在为CPU编写仿真器时,我错过了上述内容
可以说我有一个结构:
struct Foo {
char a; // read and written to by thread 1 only
char b; // read and written to by thread 2 only
};
Run Code Online (Sandbox Code Playgroud)
根据我的理解,当两个线程在两个不同的内存位置上运行时,C++标准保证了上述的安全性.
我想尽管如此,因为char a和char b属于同一个缓存行,所以编译器必须进行额外的同步.
这到底发生了什么?
我想知道为什么对Float64值进行操作比对 进行操作更快Float16:
julia> rnd64 = rand(Float64, 1000);\n\njulia> rnd16 = rand(Float16, 1000);\n\njulia> @benchmark rnd64.^2\nBenchmarkTools.Trial: 10000 samples with 10 evaluations.\n Range (min \xe2\x80\xa6 max): 1.800 \xce\xbcs \xe2\x80\xa6 662.140 \xce\xbcs \xe2\x94\x8a GC (min \xe2\x80\xa6 max): 0.00% \xe2\x80\xa6 99.37%\n Time (median): 2.180 \xce\xbcs \xe2\x94\x8a GC (median): 0.00%\n Time (mean \xc2\xb1 \xcf\x83): 3.457 \xce\xbcs \xc2\xb1 13.176 \xce\xbcs \xe2\x94\x8a GC (mean \xc2\xb1 \xcf\x83): 12.34% \xc2\xb1 3.89%\n\n \xe2\x96\x81\xe2\x96\x88\xe2\x96\x88\xe2\x96\x84\xe2\x96\x82\xe2\x96\x82\xe2\x96\x86\xe2\x96\x86\xe2\x96\x84\xe2\x96\x82\xe2\x96\x81 \xe2\x96\x82\xe2\x96\x86\xe2\x96\x84\xe2\x96\x81 \xe2\x96\x82\xe2\x96\x82\xe2\x96\x82\xe2\x96\x81 \xe2\x96\x82\n \xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x87\xe2\x96\x87\xe2\x96\x86\xe2\x96\x86\xe2\x96\x87\xe2\x96\x86\xe2\x96\x85\xe2\x96\x87\xe2\x96\x88\xe2\x96\x88\xe2\x96\x86\xe2\x96\x86\xe2\x96\x85\xe2\x96\x85\xe2\x96\x86\xe2\x96\x84\xe2\x96\x84\xe2\x96\x81\xe2\x96\x81\xe2\x96\x83\xe2\x96\x83\xe2\x96\x81\xe2\x96\x81\xe2\x96\x84\xe2\x96\x81\xe2\x96\x83\xe2\x96\x84\xe2\x96\x81\xe2\x96\x83\xe2\x96\x81\xe2\x96\x84\xe2\x96\x83\xe2\x96\x81\xe2\x96\x81\xe2\x96\x86\xe2\x96\x87\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x87 \xe2\x96\x88\n 1.8 \xce\xbcs Histogram: log(frequency) by time 10.6 \xce\xbcs <\n\n …Run Code Online (Sandbox Code Playgroud) 在大多数处理器中,为什么L1缓存的大小小于L2缓存的大小?
假设我们有两个线程,一个是在循环中读取bool而另一个可以在特定时间切换它.我个人认为这应该是原子的,因为sizeof(bool)在C++中是1个字节而你不是部分读/写字节但我想100%肯定.
那么是或否?
编辑:
另外供将来参考,同样适用于int?
我看到一个简单的存储循环出乎意料地表现不佳,这个存储循环有两个存储:一个具有16字节的正向步长,另一个总是位于同一位置1,如下所示:
volatile uint32_t value;
void weirdo_cpp(size_t iters, uint32_t* output) {
uint32_t x = value;
uint32_t *rdx = output;
volatile uint32_t *rsi = output;
do {
*rdx = x;
*rsi = x;
rdx += 4; // 16 byte stride
} while (--iters > 0);
}
Run Code Online (Sandbox Code Playgroud)
在汇编这个循环可能3看起来像:
weirdo_cpp:
...
align 16
.top:
mov [rdx], eax ; stride 16
mov [rsi], eax ; never changes
add rdx, 16
dec rdi
jne .top
ret
Run Code Online (Sandbox Code Playgroud)
当访问的存储区域在L2中时,我希望每次迭代运行少于3个周期.第二个商店只是一直在同一个位置,应该添加一个周期.第一个商店意味着从L2引入一条线,因此每4次迭代也会驱逐一条线.我不确定你如何评估L2成本,但即使你保守估计L1只能在每个周期中执行以下操作之一:(a)提交商店或(b)从L2接收一行或(c)将一条线驱逐到L2,对于stride-16商店流,你会得到1 + 0.25 + …
据我所知,C中最小的单位是a byte.这种约束来自哪里?中央处理器?
例如,如何将一个nibble或一个单独写入bit文件?