5

Does anybody know how to make an atomic boolean in iOS 10?

Current code:

import UIKit

struct AtomicBoolean {
    fileprivate var val: UInt8 = 0

    /// Sets the value, and returns the previous value.
    /// The test/set is an atomic operation.
    mutating func testAndSet(_ value: Bool) -> Bool {
       if value {
           return OSAtomicTestAndSet(0, &val)
       } else {
           return OSAtomicTestAndClear(0, &val)
       }
    }

    /// Returns the current value of the boolean.
    /// The value may change before this method returns.
    func test() -> Bool {
      return val != 0
    }
}

The code works as expected, but i keep getting the warning:

'OSAtomicTestAndSet' was deprecated in iOS 10.0: Use atomic_fetch_or_explicit(memory_order_relaxed) from <stdatomic.h> instead

I can't get it to work with atomic_fetch_or_explicit(memory_order_relaxed).

Does anyone know how to convert my current code to iOS 10, in order to get rid of this warning?

Thank you!

PAK
  • 431
  • 4
  • 17
  • 1
    The focus of the question should probably be how to get `atomic_fetch_or_explicit` to work. To do that though, you'd need to show your attempt to use it, and say what failed. – Carcigenicate Jun 21 '17 at 20:00
  • Compare https://stackoverflow.com/questions/39356873/swift-3-atomic-compare-exchange-strong. – The compiler warns about deprecated OSAtomic functions, but does not import the functions from ``. – Martin R Jun 21 '17 at 20:11

3 Answers3

4

the better way is to avoid it ... If you would like to mimick it just to synchronise access to your AtomicBoolean, use synchronisation avaiable in GCD

for example

import PlaygroundSupport
import Foundation
import Dispatch

PlaygroundPage.current.needsIndefiniteExecution = true

let q = DispatchQueue(label: "print")

struct AtomicBoolean {
    private var semaphore = DispatchSemaphore(value: 1)
    private var b: Bool = false
    var val: Bool  {
        get {
            q.async {
                print("try get")
            }
            semaphore.wait()
            let tmp = b
            q.async {
                print("got", tmp)
            }
            semaphore.signal()
            return tmp
        }
        set {
            q.async {
                print("try set", newValue)
            }
            semaphore.wait()
            b = newValue
            q.async {
                print("did", newValue)
            }
            semaphore.signal()
        }
    }

}
var b = AtomicBoolean()

DispatchQueue.concurrentPerform(iterations: 10) { (i) in
    if (i % 4 == 0) {
        _ = b.val
    }
    b.val = (i % 3 == 0)
}

prints

try get
try set false
try set false
try set true
did false
got false
try get
try set true
did false
try set false
did true
did true
try set true
try set false
got false
try set false
did false
try get
did true
try set true
did false
did false
got false
try set false
did true
did false
user3441734
  • 16,722
  • 2
  • 40
  • 59
0

Apple confirmed that read and write of Bool value is not an atomic operation in Swift.

But there are many ways to synchronize.

Example

Somewhere add below global-function logic:

func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

And use like:

let myLock = NSObject();

// ...

synchronized(myLock) {
    // Something not thread safe here...
}
Top-Master
  • 7,611
  • 5
  • 39
  • 71
0

Your first option is to...

  1. just use a regular lock and guard your value access, the other is...
  2. to use Swift Atomics

Then you can just say

var value = ManagedAtomic<UInt8>(0)

// Atomic store
value.store(2, ordering: .relaxed)

// Atomic load
value.load(ordering: .relaxed)
  • Swift atomics only available through SPM, is there any way we can make framework file because my targeted project is chromium and it does not have spm support. – Muhammad Shauket Jan 17 '22 at 07:31