Home > Net >  Is it possible to build a atomic "release-and-acquire" operation on two locks in riscv?
Is it possible to build a atomic "release-and-acquire" operation on two locks in riscv?

Time:08-16

Is it possible to build a atomic "release-and-acquire" operation in riscv so one could release a lock then immediately acquire another one atomically?

I found that most of riscv locking mechanism is implemented using atomic swap amoswap.w.aq, however it does not appear to support swapping between two memory location, only between a memory location and a register.

I'm also aware of the existence of LR/SC (load-reserved/store-conditional) instructions in riscv, but it doesn't seems to support such transactional memory scheme between multiple memory addresses.

CodePudding user response:

"Atomically exchange memory with memory" is an unusual thing for CPUs to support, in general. (The MC68030 is notable as one of the few historical machines that did support it.) In most cases you're expected to just protect both objects with a single mutex. So if you need to atomically drop one lock and take another, you would need a third lock to protect the pair of them.

Another option is to represent your locks as different bits or bitfields within a single machine word, if they will fit. Then you can use an LL/SC pair to atomically twiddle whatever combination of them you need. But this comes at the cost of higher contention; now all threads that are using any of the locks are contending for access to the same word.

Some architectures offer a double-word LL/SC or compare-and-swap, so that you can actually use two adjacent machine words (also useful for lock-free linked lists and such), but it appears that RISC-V does not.

CodePudding user response:

@ErikEidt helped me by asking the correct question in the comment:

If the other lock is not available, what should it do? In your senario, does having the first lock somehow guarantee the second lock is available?

I have thought it through, and it does seem like a strange thing to demand such atomic "release-then-acquire" operation.

If having the first lock A guarantees the second lock B is available:

  • then it's just equivalent to acquire(B); release(A);, where acquire(B) will always succeed. (also impossible for a deadlock to occur)

If it does not have such guarantee, then while B is not available:

  • suppose the operation spins for lock B with lock A still being held, then it's the same as acquire(B); release(A); again. (can potentially deadlock)
  • if it spins for B after releasing lock A, then what it does is just release(A); acquire(B);

My initial intention is to use such operation to resolve the deadlock issue caused by the switching between two locks. But seems like all this "release-then-acquire" operation will do is just the same as plain acquire and release as two separate operations. Might have to think more about my concurrency design. :\

  • Related