8.1.2总线锁定
Intel 64和IA-32处理器提供LOCK#信号,该信号在某些关键存储器操作期间自动置位,以锁定系统总线或等效链路.当该输出信号被断言时,来自其他处理器或总线代理的用于控制总线的请求被阻止.软件可以指定在遵循LOCK语义的其他情况下将LOCK前缀添加到指令之前.
它来自英特尔手册,第3卷
听起来内存上的原子操作将直接在内存(RAM)上执行.我很困惑,因为当我分析装配输出时,我看到"没什么特别的".基本上,生成的汇编输出std::atomic<int> X; X.load()只会产生"额外"的影响.但是,它负责正确的内存排序,而不是原子性.如果我理解得X.store(2)恰到好处mov [somewhere], $2.就这样.它似乎没有"跳过"缓存.我知道将对齐(例如int)移动到内存是原子的.但是,我很困惑.
所以,我提出了疑问,但主要问题是:
好的,所以我正在阅读有关同步的内容,并且我阅读了各种算法,例如自旋锁,信号量和互斥锁,以避免竞争条件.
但是,当多个进程完全同时访问数据时,这些算法无法阻止SMP中的竞争条件.
例如,假设处理器A中的线程1运行锁定(mutex1); 退出(1000); 解锁(mutex1);
处理器B中的线程2运行锁定(mutex1); 存款(1000); 存款(1000); 解锁(mutex1);
当两个线程在相同时间运行时,两个线程将同时处于临界区.
唯一的解决方案(应该是硬件级别)将使每个处理器彼此略微偏离,但它会破坏并行性的目的.
是否有任何硬件级别支持以避免多个处理器尝试在同一时间获取锁定的情况?
(这不是原子性问题,而是精确并行问题,我想知道SMP如何处理它).
我假设简单的自旋锁不会进入操作系统等待这个问题的目的。
我发现简单的自旋锁通常使用lock xchgorlock bts代替 来实现lock cmpxchg。
cmpxchg但是如果期望不匹配,是否会避免写入该值?那么失败的尝试不是更便宜吗cmpxchg?
或者即使cmpxchg发生故障也会写入数据并使其他核心的缓存线无效?
这个问题类似于什么具体将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?,但它是特定的cmpxchg,而不是普遍的。
在过去的几天里,我读了一些有关无锁编程的知识,我遍历了util.java.Random该类,并使用以下例程创建了它:
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
Run Code Online (Sandbox Code Playgroud)
根据这个 SO答案:
所谓的无锁算法倾向于对CAS指令使用严格的忙等待,但是在通常情况下竞争很低,以至于CPU通常只需要迭代几次。
和维基百科:
研究人员发现,在CAS处理失败后,无需立即重试,而是可以提高多处理器系统的整体系统性能,在多处理器系统中,如果看到CAS失败的线程使用指数退避,则许多线程会不断更新某些特定的共享变量,换句话说,请等待重试CAS之前需要一点时间。[4]
维基百科文章是否可以理解,已经找到但尚未使用,或者CAS指令在失败后人为地退缩是常见的做法。这是因为这样的循环对于cpu的使用不被认为是危险的,还是因为CAS一直没有引起争议?
第二个问题:是否有seed创建引用的特定原因,还是我们也可以简单地使用类作用域中的变量?
在基于 CAS 的循环中,例如下面的循环,使用暂停对 x86 有益吗?
void atomicLeftShift(atomic<int>& var, int shiftBy)
{
While(true) {
int oldVal = var;
int newVal = oldVal << shiftBy;
if(var.compare_exchange_weak(oldVal, newVal));
break;
else
_mm_pause();
}
}
Run Code Online (Sandbox Code Playgroud) 我是低级别的新手,所以我完全忘记了你可能面临的问题,我甚至不确定我是否理解"原子"一词.现在我试图通过扩展程序集围绕内存操作进行简单的原子锁.为什么?为了好奇.我知道我在这里重新发明轮子,可能会过度简化整个过程.
这个问题? 我在这里提供的代码是否实现了使内存操作既线程安全又可重入的目标?
我只想做...
代码:
volatile int atomic_gate_memory = 0;
static inline void atomic_open(volatile int *gate)
{
asm volatile (
"wait:\n"
"cmp %[lock], %[gate]\n"
"je wait\n"
"mov %[lock], %[gate]\n"
: [gate] "=m" (*gate)
: [lock] "r" (1)
);
}
static inline void atomic_close(volatile int *gate)
{
asm volatile (
"mov %[lock], %[gate]\n"
: [gate] "=m" (*gate)
: [lock] "r" (0)
);
}
Run Code Online (Sandbox Code Playgroud)
然后像:
void *_malloc(size_t size)
{
atomic_open(&atomic_gate_memory);
void *mem = malloc(size);
atomic_close(&atomic_gate_memory); …Run Code Online (Sandbox Code Playgroud)