细说常见的原子操作 (CAS)和(LL/SC)及常与其一起使用的仲裁(Arbitration)

发布于:2024-05-07 ⋅ 阅读:(25) ⋅ 点赞:(0)

目录

1.Compare-and-swap (CAS)

(1)比较(Compare):

(2)交换(Swap):

(3)优点:

(4)缺点:

2.Load-Linked/Store-Conditional(LL/SC)

3.仲裁(Arbitration)


1.Compare-and-swap (CAS)

        Compare-and-swap (CAS) 是一种常见的原子操作,它包含两个步骤:比较和交换。CAS 操作通常用于实现锁和其他同步机制,确保数据的正确性和一致性。 CAS 操作的步骤如下:

(1)比较(Compare):

        CAS 操作首先比较内存中的某个值是否与期望的值相匹配。如果匹配,则进行下一步;否则,放弃这次操作。

(2)交换(Swap):

        如果比较成功,CAS 操作会将该内存位置的值更新为一个新的值。        

(3)优点:

        整个 CAS 操作过程保证是原子性的,即不可被中断。这确保了即使在多线程环境中,也不会有其他线程在执行这个操作的过程中干扰它。

        CAS 操作通常用于实现无锁数据结构,如无锁栈、无锁队列等,以及其他需要线程安全性的场景。由于它的非阻塞性质,CAS 操作可以提高多线程程序的性能,避免线程长时间等待锁资源。

(4)缺点:

        然而,CAS 也有其局限性。例如,它可能导致“ABA”问题,即一个值从 A 改为 B,然后又改回 A,尽管这个值变化了,但由于 CAS 只比较是否与期望值相等,因此可能会错过这种变化。为了解决这个问题,可以使用版本号或者其他方式来标记数据是否被修改过。

       一些编程语言中提供了对应的 API(如 `Atomic` 类)来支持 CAS 操作,使得程序员能够在代码中轻松地使用这些原子操作来保证线程安全性。

2.Load-Linked/Store-Conditional(LL/SC)

        Load-Linked/Store-Conditional(LL/SC)是一种用于实现原子操作的指令集,通常在多处理器系统中使用,以确保在多个处理器访问共享数据时的一致性。

        Load-Linked指令(LL)用于读取内存中的数据,并将其链接到处理器的某个寄存器中。同时,它还能够设置一个标志位来指示该操作是否成功。如果在同一时刻另一个处理器对同一内存位置进行了修改,那么这个标志位将会被设置为失败,表明这次读取操作不是原子的。

        Store-Conditional指令(SC)则用于根据之前LL指令的结果来有条件地写入内存。如果LL指令成功(即没有其他处理器修改了该内存位置),SC指令将会把寄存器中的数据写入到内存中,否则,它将放弃这次写操作并返回失败状态。

       通过这种方式,LL/SC指令可以用来实现更为复杂的原子操作,如比较并交换(Compare-and-Swap, CAS)、加法和递增等。这些操作对于同步原语、锁和其他并发控制机制至关重要。

        LL/SC指令并不是所有处理器架构都支持,而且它们的具体实现细节可能因架构而异。在某些情况下,这些指令可能会被编译器或运行时环境转换为其他形式的原子操作,以便在不支持LL/SC的硬件上执行。

3.仲裁(Arbitration)

        仲裁(Arbitration)本身并不直接属于原子操作,但它常常与原子操作一起使用,以确保在多线程或分布式系统中对共享资源的正确访问和管理。

        仲裁通常指的是在多个竞争者之间确定一个胜出者的流程,这个胜出者可以是线程、进程或者计算节点等。在多线程环境中,仲裁可能用于决定哪个线程可以接下来获得对某个共享资源的独占访问权。在分布式系统中,仲裁可能用于选举一个领导者或者确定一个全局的顺序。

        为了实现仲裁,往往需要一些原子操作,如比较和交换(CAS)、加载链接/条件存储(LL/SC)或者测试并设置(Test-and-Set)等。这些原子操作可以用来保证在竞争状态下,对共享状态的修改是正确的并且是原子的。

        例如,在基于锁的仲裁中,原子的锁获取和释放操作可以确保只有一个线程能够持有锁,从而保证资源的独占使用。在无锁仲裁中,CAS 操作可以用来比较当前状态并原子性地更新它,以此来避免锁的使用并提高并发性能。

        所以,虽然仲裁不是一个直接的原子操作,但在设计高并发和分布式系统时,它是确保线程安全和正确性的关键机制之一,而原子操作则是其实现的基础工具。