这五个指令都是用来实现原子操作的,也就是在并发编程中保证线程安全的操作。
具体来说:
测试并设置(Test-and-Set)指令是指在执行写操作之前,先读取一个值,并将这个值和一个预设的值进行比较,如果相等,则将一个新值写入该位置。这个指令常用于实现锁的获取操作,通过原子地测试并设置一个标志位,判断锁是否被占用,并将锁的状态设置为占用。
获取并增加(Fetch-and-Increment)指令是指将一个内存位置的值加上一个给定的值,并返回加之前的原值。这个指令常用于实现计数器等数据结构,保证在并发修改时能够正确地增加计数器的值。
交换(Swap)指令是指将一个内存位置的值和一个给定的值进行交换,并返回原来的值。这个指令常用于实现互斥量(Mutex)等同步原语,可以保证在多个线程之间交换互斥量的状态,从而实现同步。
比较并交换(Compare-and-Swap,CAS)指令是指读取一个内存位置的值,与一个期望值进行比较,如果相等则将该位置的值更新为一个新值。CAS指令是实现乐观锁的基础,可以用来解决多个线程同时修改一个变量时出现的竞态条件问题。
加载链接/条件储存(Load-Linked/Store-Conditional,LL/SC)指令是一对指令,LL指令用来读取内存中的值,并在处理器缓存中建立一个链接,SC指令用来检查缓存中链接对应的内存位置是否被修改过,如果没有则将新值写入该位置。LL/SC指令是实现一些复杂同步原语的基础,例如基于事务的内存模型。
测试并设置(Test-and-Set) 和 比较并交换(Compare-and-Swap,CAS)
测试并设置(Test-and-Set)和比较并交换(Compare-and-Swap,CAS)两种操作都是用于实现同步原语的硬件支持指令,但它们是有区别的。
Test-and-Set操作会原子性地将指定的内存位置设置为“已锁定”,并返回该位置在操作前的值。如果操作前的值为“已锁定”,则该操作会一直阻塞直到该位置变为“未锁定”。这种操作在多线程环境中可以用于实现互斥锁,即一个线程获取到锁之后,其他线程都必须等待该线程释放锁之后才能获取锁。
而CAS操作也是一种原子操作,它将指定内存位置的值与期望的值进行比较,如果相等则将该位置的值更新为新值,并返回更新前的旧值;否则不做任何操作,返回当前位置的值。这种操作在多线程环境中可以用于实现无锁算法,即多个线程可以同时访问共享资源而不需要使用锁进行同步,从而提高并发性能。
因此,虽然Test-and-Set和CAS操作都是用于实现同步原语的硬件支持指令,但它们的应用场景和使用方式是不同的。
交换(Swap)是什么?
交换(Swap)指的是将两个变量的值进行交换,通常需要使用一个中间变量来完成。而在硬件层面,交换指令可以直接完成这个操作,而且是原子性的。
下面是一个使用交换指令进行变量交换的示例代码:
public class SwapExample {private static int x = 10;private static int y = 20;public static void main(String[] args) {System.out.println("Before swap: x=" + x + ", y=" + y);swap();System.out.println("After swap: x=" + x + ", y=" + y);}private static void swap() {// 使用交换指令交换x和y的值int tmp = x;x = y;y = tmp;}
}
输出结果为:
Before swap: x=10, y=20
After swap: x=20, y=10
可以看到,使用交换指令可以非常方便地完成变量交换的操作。
交换(Swap)指令常用于实现互斥量等同步原语,因为它可以实现原子性操作,即在多个线程之间交换互斥量的状态时,保证操作的原子性和线程安全性。
考虑使用交换指令来实现互斥量的例子,假设有两个线程 A 和 B,它们都需要访问一个共享资源。在代码中,使用一个整型变量 mutex 来表示互斥量,当 mutex 的值为 0 时,表示共享资源没有被占用,可以被线程 A 占用,当 mutex 的值为 1 时,表示共享资源已经被占用,线程 A 必须等待线程 B 释放该资源后才能继续访问。
使用交换指令实现互斥量的代码如下:
int mutex = 0; // 初始值为 0// 线程 A 访问共享资源
while (true) {while (mutex == 1); // 等待共享资源被释放if (compareAndSwap(&mutex, 0, 1)) { // 使用交换指令尝试占用互斥量// 访问共享资源...// 释放互斥量swap(&mutex, 0); // 使用交换指令释放互斥量break;}
}// 线程 B 访问共享资源
while (true) {while (mutex == 0); // 等待共享资源被占用if (compareAndSwap(&mutex, 1, 0)) { // 使用交换指令尝试释放互斥量// 释放共享资源...break;}
}
在上述代码中,compareAndSwap() 函数是比较并交换指令,用于尝试占用或释放互斥量。当 mutex 的值为 0 时,compareAndSwap() 将 mutex 的值设置为 1,并返回原来的值;当 mutex 的值为 1 时,compareAndSwap() 不会修改 mutex 的值,并返回原来的值。通过不断地使用交换指令和比较并交换指令,可以实现线程间对共享资源的互斥访问,从而保证同步和线程安全性。
加载链接/条件储存(Load-Linked/Store-Conditional,LL/SC)指令是一对指令举例说明:
import java.util.concurrent.atomic.AtomicReference;public class SpinLock {private AtomicReference owner = new AtomicReference();private int count = 0;public void lock() {Thread current = Thread.currentThread();if (owner.get() == current) {++count;return;}while (!owner.compareAndSet(null, current)) {// spin}}public void unlock() {Thread current = Thread.currentThread();if (owner.get() != current) {throw new IllegalMonitorStateException("Calling thread has not locked this lock");}if (--count == 0) {owner.set(null);}}
}
LL/SC指令通常是在处理器的指令集中实现的,因此具体实现方式可能有所不同。下面是一个简单的示例,使用LL/SC指令来实现一个简单的自旋锁:
import java.util.concurrent.atomic.AtomicReference;public class SpinLock {private AtomicReference owner = new AtomicReference();private int count = 0;public void lock() {Thread current = Thread.currentThread();if (owner.get() == current) {++count;return;}while (!owner.compareAndSet(null, current)) {// spin}}public void unlock() {Thread current = Thread.currentThread();if (owner.get() != current) {throw new IllegalMonitorStateException("Calling thread has not locked this lock");}if (--count == 0) {owner.set(null);}}
}
这个自旋锁使用一个AtomicReference
对象来存储锁的拥有者线程。当线程尝试获取锁时,它会先检查锁是否已经被当前线程持有,如果是,则直接增加计数器;否则,它会自旋地调用owner.compareAndSet(null, current)
方法来尝试获取锁。该方法使用了LL/SC指令,它会先读取owner
的值,并在处理器缓存中建立一个链接。然后,它会检查该值是否为null
,如果是,则将其设置为当前线程并返回true
,否则返回false
。如果返回false
,则说明有其他线程已经持有了锁,当前线程需要自旋等待。
当线程释放锁时,它会先检查锁是否已经被当前线程持有,如果不是,则抛出一个IllegalMonitorStateException
异常。否则,它会将计数器减1。如果计数器为0,则说明锁已经完全释放,此时将owner
设置为null
。注意,这里不需要使用LL/SC指令,因为这个操作只需要在当前线程的处理器缓存中进行,不需要和其他处理器进行通信。
上一篇:医院信息管理云平台源码 云HIS系统源码 4级电子病历系统
下一篇:Ubuntu mujoco安装:Missing path to your environment variable. 解决方案