为什么store_idx_x86()的汇编输出和store_idx()一样,load_idx_x86()和load_idx()一样?
我的理解是 __atomic_load_n() 会刷新核心的失效队列,而 __atomic_store_n() 会刷新核心的存储缓冲区。
注意——我遵守了:gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16)
更新:我知道 x86 永远不会用其他存储重新排序存储并用其他负载加载——所以 gcc 足够聪明,只在需要时才实现 sfence 和 lfence,或者应该使用 __atomic_ 导致栅栏(假设内存模型比__ATOMIC_RELAXED)?
代码
#include <stdint.h>
inline void store_idx_x86(uint64_t* dest, uint64_t idx)
{
*dest = idx;
}
inline void store_idx(uint64_t* dest, uint64_t idx)
{
__atomic_store_n(dest, idx, __ATOMIC_RELEASE);
}
inline uint64_t load_idx_x86(uint64_t* source)
{
return *source;
}
inline uint64_t load_idx(uint64_t* source)
{
return __atomic_load_n(source, __ATOMIC_ACQUIRE);
}
Run Code Online (Sandbox Code Playgroud)
集会:
.file "util.c"
.text
.globl store_idx_x86
.type store_idx_x86, @function
store_idx_x86:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset …Run Code Online (Sandbox Code Playgroud) 我正在实现一个基于此算法的无锁队列,该算法使用计数器来解决ABA问题.但我不知道如何用c ++ 11 CAS实现这个计数器.例如,从算法:
E9: if CAS(&tail.ptr->next, next, <node, next.count+1>)
Run Code Online (Sandbox Code Playgroud)
它是一个原子操作,意思是如果tail.ptr->next等于next,则tail.ptr->next指向node并同时(原子地)产生next.count+1.但是,使用C++ 11 CAS,我只能实现:
std::atomic_compare_exchange_weak(&tail.ptr->next, next, node);
Run Code Online (Sandbox Code Playgroud)
这不可能next.count+1同时发生.
在这里(以及一些SO问题)我看到C++不支持像无锁的东西,std::atomic<double>并且还不能支持像原子AVX/SSE向量这样的东西,因为它依赖于CPU(虽然现在我知道CPU,ARM, AArch64和x86_64有矢量).
但是double在x86_64中对s或向量的原子操作是否有汇编级支持?如果是这样,支持哪些操作(如加载,存储,添加,减去,可能相乘)?MSVC++ 2017实现哪些操作无锁atomic<double>?
在答案中,我已经声明未对齐访问的速度与对齐访问的速度几乎相同(在x86/x86_64上).我没有任何数字来支持这个陈述,所以我已经为它创建了一个基准.
你看到这个基准测试有什么缺陷吗?你可以改进它(我的意思是,增加GB /秒,所以它更好地反映了真相)?
#include <sys/time.h>
#include <stdio.h>
template <int N>
__attribute__((noinline))
void loop32(const char *v) {
for (int i=0; i<N; i+=160) {
__asm__ ("mov (%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x04(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x08(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x0c(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x10(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x14(%0), %%eax" : : "r"(v) :"eax");
__asm__ ("mov 0x18(%0), %%eax" : : "r"(v) :"eax"); …Run Code Online (Sandbox Code Playgroud) 我们继承了一个针对瑞萨RX231微控制器的项目,我一直在关注它.
该uC只有一条指令锁定总线的原子性(XCHG).
因为处理器是访问RAM存储器的唯一组件(没有使用DMA或DTC),要操纵用户代码中与中断共享的变量,所以中断被禁用(在处理器状态字寄存器中)以获取访问时间,即
disable_interrupts(); /* set_psw(get_psw() & ~(1 << 16)); */
/* access or modify shared variables */
enable_interrupts(); /* set_psw(get_psw() | (1 << 16)); */
Run Code Online (Sandbox Code Playgroud)
但是,还有"标志"在没有保护的情况下共享,这些标志在中断中设置并以下列方式在用户代码中轮询:
volatile unsigned char event_request_message = 0;
unsigned char condition_sending_message = 0;
#pragma interrupt
void on_request_message()
{
...
event_request_message = 1; // mov.l #0x3df5, r14
// mov.b #1, [r14]
...
}
void user_code()
{
for(;;)
{
...
/* might be evaluated multiple times before transmit message is completed */
if(event_request_message && !condition_sending_message) // mov.l …Run Code Online (Sandbox Code Playgroud) 通常,缓存行是 64B,但非易失性内存的原子性是 8B。
例如:
x[1]=100;
x[2]=100;
clflush(x);
Run Code Online (Sandbox Code Playgroud)
x缓存行对齐,并且最初设置为0。
系统崩溃 clflush();
是否有可能x[1]=0,x[2]=100重新启动后?
我正在学习有关CPU高速缓存的信息,但是现在我仍然对高速缓存一致性协议(MESI)有误解。想象一下,我们有2个内核在共享状态下有一条缓存行。其中一个执行读取,另一个执行写入:
;mem is cached in Shared state
Thread 1 (core 1) Thread 2 (core 2)
mov rax, [mem] mov [mem], dword 1
Run Code Online (Sandbox Code Playgroud)
核心1可以观察到某些中间状态。我的意思是这样的:
Core 2将缓存行标记L1D为已修改,并将更改写入其中。core 1的L1D高速缓存仍处于Shared状态,所以读恰好读取陈旧的价值。core 1的L1D缓存中的行标记为无效。英特尔的MESI / MESIF实施中是否可能出现这种情况?
struct Data {
double a;
double b;
double c;
};
Run Code Online (Sandbox Code Playgroud)
如果在不同的线程上读取,但只有一个其他线程正在写入 a、b、c 中的每一个,那么读取每个双精度值是否正常?
如果我确保Data对齐,会出现什么情况?
struct Data {double a,b,c; } __attribute__((aligned(64));
Run Code Online (Sandbox Code Playgroud)
这将确保 a,b,c 中的每一个都对齐到 64,64+8, 64+16... 所以总是对齐到 8*8=64 位边界。
这个问题对原子 x86 指令的对齐要求及其答案让我认为Data::a/b/c从另一个线程写入并同时读取它们而不使用std::atomic.
是的,我知道std::atomic会解决这个问题,但这不是问题。
假设我有多个线程访问相同的内存位置。而且,如果有的话,它们都写入相同的值,但没有人读取它。之后,所有线程(通过锁)收敛,然后我才读取值。我需要为此使用原子吗?这是针对 x86_64 系统的。该值是一个 int32。
正如我从测试用例中看到的:https : //godbolt.org/z/K477q1
生成的程序集加载/存储原子放松与普通变量相同:ldr 和 str
那么,松弛原子变量和普通变量之间有什么区别吗?