Skip to content

Instantly share code, notes, and snippets.

@cbarrett
Last active March 9, 2017 04:13
Show Gist options
  • Save cbarrett/7b5295f88840d21371b1f05efaf5a6f9 to your computer and use it in GitHub Desktop.
Save cbarrett/7b5295f88840d21371b1f05efaf5a6f9 to your computer and use it in GitHub Desktop.
Simple atomic pointer
// Copyright (c) 2017 Colin Barrett, all rights reserved.
// License freely granted under the terms of CC-BY-NC <https://creativecommons.org/licenses/by-nc/4.0/>.
import Darwin
public class AtomicPointer<Pointee>: Equatable {
fileprivate var ptr: UnsafeMutablePointer<Pointee?>
fileprivate var flag: atomic_flag = atomic_flag()
public init(_ pointee: inout Pointee?) {
precondition(pointee != nil)
ptr = UnsafeMutablePointer.allocate(capacity: 1)
ptr.moveInitialize(from: &pointee, count: 1)
pointee = nil
}
public func load() -> Pointee? {
while atomic_flag_test_and_set_explicit(&flag, memory_order_acquire) {}
defer { atomic_flag_clear_explicit(&flag, memory_order_release) }
return ptr.pointee
}
public static func ==(_ lhs: AtomicPointer<Pointee>, _ rhs: AtomicPointer<Pointee>) -> Bool {
return lhs.ptr == rhs.ptr
}
}
extension AtomicPointer where Pointee: Equatable {
public func compareAndSwap(_ expected: Pointee, _ desired: inout Pointee?) -> Bool {
precondition(desired != nil)
if atomic_flag_test_and_set_explicit(&flag, memory_order_consume) {
return false
}
defer { atomic_flag_clear_explicit(&flag, memory_order_release) }
var old = ptr.move()
guard old == expected else {
ptr.moveInitialize(from: &old, count: 1)
return false
}
ptr.moveInitialize(from: &desired, count: 1)
desired = nil
return true
}
}
@cbarrett
Copy link
Author

cbarrett commented Mar 8, 2017

Here's my first attempt—not sure if it works or not yet

@diogot
Copy link

diogot commented Mar 8, 2017

You can use defer in compareAndSwap for atomic_thread_fence(memory_order_release)

@cbarrett
Copy link
Author

cbarrett commented Mar 8, 2017

Updated with some rejiggering.

@cbarrett
Copy link
Author

cbarrett commented Mar 9, 2017

Using atomic_flag to (hopefully) implement CAS properly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment