相关疑难解决方法(0)

num ++是'int num'的原子吗?

一般地,对于int num,num++(或++num),作为读-修改-写操作中,是不是原子.但我经常看到编译器,例如GCC,为它生成以下代码(在这里尝试):

在此输入图像描述

由于第5行对应于num++一条指令,我们可以得出结论,在这种情况下num++ 是原子的吗?

如果是这样,是否意味着如此生成num++可以在并发(多线程)场景中使用而没有任何数据争用的危险(例如,我们不需要制作它,std::atomic<int>并强加相关成本,因为它是无论如何原子)?

UPDATE

请注意,这个问题不是增量是否原子的(它不是,而且是问题的开头行).它是否可以在特定场景中,即在某些情况下是否可以利用单指令性质来避免lock前缀的开销.而且,作为公认的答案约单处理器的机器,还有部分提到这个答案,在其评论和其他人谈话解释,它可以(尽管不是C或C++).

c c++ assembly multithreading atomic

148
推荐指数
8
解决办法
1万
查看次数

x86中"PAUSE"指令的目的是什么?

我正在尝试创建一个自旋锁的哑版.浏览网页时,我在x86中遇到了一个名为"PAUSE"的汇编指令,该指令用于向处理器提供当前在此CPU上运行自旋锁的提示.英特尔手册和其他可用信息说明了这一点

在大多数情况下,处理器使用此提示来避免内存顺序违规,从而大大提高了处理器性能.因此,建议在所有自旋等待循环中放置PAUSE指令.文档还提到"等待(一些延迟)"是指令的伪实现.

上段的最后一行很直观.如果我没有成功抓住锁,我必须等待一段时间然后再抓住锁.

但是,在旋转锁定的情况下,内存顺序违规是什么意思?"内存顺序违规"是否意味着旋转锁定后指令的错误推测加载/存储?

关于堆栈溢出之前已经询问了自旋锁定问题但是内存顺序违规问题仍未得到解决(至少对于我的理解).

parallel-processing x86 x86-64 intel critical-section

53
推荐指数
2
解决办法
8336
查看次数

最快的内联装配螺旋锁

我正在用c ++编写多线程应用程序,其中性能至关重要.我需要在线程之间复制小结构时使用大量锁定,为此我选择使用自旋锁.

我已经做了一些研究和速度测试,我发现大多数实现大致同样快:

  • MicroFts CRITICAL_SECTION,SpinCount设置为1000,得分约140个单位
  • 使用Microsofts 实现此算法 InterlockedCompareExchange得分约95个时间单位
  • 我也尝试使用一些内联汇编,__asm {}使用类似这样的代码,它得分约70个时间单位,但我不确定是否已创建适当的内存屏障.

编辑:这里给出的时间是2个线程锁定和解锁螺旋锁1,000,000次所需的时间.

我知道这并没有太大的区别,但是由于自旋锁是一个使用频繁的对象,人们会认为程序员会同意以最快的方式制作自旋锁.谷歌搜索导致许多不同的方法.我认为如果使用内联汇编并使用指令而不是比较32位寄存器来实现上述方法将是最快的CMPXCHG8B.此外,必须考虑内存障碍,这可以通过LOCK CMPXHG8B(我认为?)来完成,这保证了内核之间共享内存的"专有权".最后[有人建议]对于繁忙的等待应该伴随NOP:REP,这将使超线程处理器切换到另一个线程,但我不确定这是否是真的?

根据我对不同螺旋锁的性能测试,可以看出没有太大区别,但出于纯粹的学术目的,我想知道哪一个是最快的.但是由于我在汇编语言和内存障碍方面的经验非常有限,如果有人可以为我在LOCK CMPXCHG8B中提供的最后一个示例编写汇编代码并在以下模板中使用适当的内存屏障,我会很高兴:

__asm
{
     spin_lock:
         ;locking code.
     spin_unlock:
         ;unlocking code.
}
Run Code Online (Sandbox Code Playgroud)

c++ x86 assembly spinlock memory-barriers

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

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

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

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

  • 如果它有效,为什么?
  • 如果它不起作用,为什么?
  • 还不够好?我应该在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
查看次数