相关疑难解决方法(0)

为什么在x86上对自然对齐的变量进行整数赋值?

我一直在读这篇关于原子操作的文章,它提到了32位整数赋值在x86上是原子的,只要该变量是自然对齐的.

为什么自然对齐确保原子性?

c c++ concurrency x86 atomic

28
推荐指数
2
解决办法
5386
查看次数

x86上的原子性

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)移动到内存是原子的.但是,我很困惑.


所以,我提出了疑问,但主要问题是:

CPU如何在内部实现原子操作?

c++ x86 multithreading atomic memory-barriers

18
推荐指数
1
解决办法
5684
查看次数

如果不同处理器中的两个进程试图在同一时间获得锁定会发生什么

好的,所以我正在阅读有关同步的内容,并且我阅读了各种算法,例如自旋锁,信号量和互斥锁,以避免竞争条件.

但是,当多个进程完全同时访问数据时,这些算法无法阻止SMP中的竞争条件.

例如,假设处理器A中的线程1运行锁定(mutex1); 退出(1000); 解锁(mutex1);

处理器B中的线程2运行锁定(mutex1); 存款(1000); 存款(1000); 解锁(mutex1);

当两个线程在相同时间运行时,两个线程将同时处于临界区.

唯一的解决方案(应该是硬件级别)将使每个处理器彼此略微偏离,但它会破坏并行性的目的.

是否有任何硬件级别支持以避免多个处理器尝试在同一时间获取锁定的情况?

(这不是原子性问题,而是精确并行问题,我想知道SMP如何处理它).

synchronization locking smp multiprocessor

12
推荐指数
1
解决办法
5884
查看次数

cmpxchg 是否会在失败时写入目标缓存行?如果不是,对于自旋锁来说它比 xchg 更好吗?

我假设简单的自旋锁不会进入操作系统等待这个问题的目的。

我发现简单的自旋锁通常使用lock xchgorlock bts代替 来实现lock cmpxchg

cmpxchg但是如果期望不匹配,是否会避免写入该值?那么失败的尝试不是更便宜吗cmpxchg

或者即使cmpxchg发生故障也会写入数据并使其他核心的缓存线无效?

这个问题类似于什么具体将 x86 缓存行标记为脏 - 任何写入,还是需要显式更改?,但它是特定的cmpxchg,而不是普遍的。

x86 assembly micro-optimization compare-and-swap cpu-cache

5
推荐指数
1
解决办法
1195
查看次数

为什么不认为CAS等效于繁忙等待循环?

在过去的几天里,我读了一些有关无锁编程的知识,我遍历了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创建引用的特定原因,还是我们也可以简单地使用类作用域中的变量?

java concurrency lock-free compare-and-swap

4
推荐指数
1
解决办法
251
查看次数

基于compare_exchange的循环是否受益于暂停?

在基于 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)

c++ x86 atomic compare-and-swap c++11

4
推荐指数
1
解决办法
610
查看次数

通过内联汇编锁定内存操作

我是低级别的新手,所以我完全忘记了你可能面临的问题,我甚至不确定我是否理解"原子"一词.现在我试图通过扩展程序集围绕内存操作进行简单的原子锁.为什么?为了好奇.我知道我在这里重新发明轮子,可能会过度简化整个过程.

这个问题? 我在这里提供的代码是否实现了使内存操作既线程安全又可重入的目标?

  • 如果它有效,为什么?
  • 如果它不起作用,为什么?
  • 还不够好?我应该在C中使用register关键字吗?

我只想做...

  • 在内存操作之前,锁定.
  • 记忆操作后,解锁.

代码:

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)

c memory assembly memory-management locking

3
推荐指数
1
解决办法
1214
查看次数