Swift 3: Atomic_Compare_Exchange_Strong

Swift 3 - Atomic boolean

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

How do I atomically increment a variable in Swift?

From Low-Level Concurrency APIs:

There’s a long list of OSAtomicIncrement and OSAtomicDecrement
functions that allow you to increment and decrement an integer value
in an atomic way – thread safe without having to take a lock (or use
queues). These can be useful if you need to increment global counters
from multiple threads for statistics. If all you do is increment a
global counter, the barrier-free OSAtomicIncrement versions are fine,
and when there’s no contention, they’re cheap to call.

These functions work with fixed-size integers, you can choose
the 32-bit or 64-bit variant depending on your needs:

class Counter {
private (set) var value : Int32 = 0
func increment () {
OSAtomicIncrement32(&value)
}
}

(Note: As Erik Aigner correctly noticed, OSAtomicIncrement32 and
friends are deprecated as of macOS 10.12/iOS 10.10. Xcode 8 suggests to use functions from <stdatomic.h> instead. However that seems to be difficult,
compare Swift 3: atomic_compare_exchange_strong and https://openradar.appspot.com/27161329.
Therefore the following GCD-based approach seems to be the best
solution now.)

Alternatively, one can use a GCD queue for synchronization.
From Dispatch Queues in the "Concurrency Programming Guide":

... With dispatch queues, you could add both tasks to a serial
dispatch queue to ensure that only one task modified the resource at
any given time. This type of queue-based synchronization is more
efficient than locks because locks always require an expensive kernel
trap in both the contested and uncontested cases, whereas a dispatch
queue works primarily in your application’s process space and only
calls down to the kernel when absolutely necessary.

In your case that would be

// Swift 2:
class Counter {
private var queue = dispatch_queue_create("your.queue.identifier", DISPATCH_QUEUE_SERIAL)
private (set) var value: Int = 0

func increment() {
dispatch_sync(queue) {
value += 1
}
}
}

// Swift 3:
class Counter {
private var queue = DispatchQueue(label: "your.queue.identifier")
private (set) var value: Int = 0

func increment() {
queue.sync {
value += 1
}
}
}

See Adding items to Swift array across multiple threads causing issues (because arrays aren't thread safe) - how do I get around that? or GCD with static functions of a struct for more sophisticated examples. This thread
What advantage(s) does dispatch_sync have over @synchronized? is also very interesting.

What's the difference between the atomic and nonatomic attributes?

The last two are identical; "atomic" is the default behavior (note that it is not actually a keyword; it is specified only by the absence of nonatomic -- atomic was added as a keyword in recent versions of llvm/clang).

Assuming that you are @synthesizing the method implementations, atomic vs. non-atomic changes the generated code. If you are writing your own setter/getters, atomic/nonatomic/retain/assign/copy are merely advisory. (Note: @synthesize is now the default behavior in recent versions of LLVM. There is also no need to declare instance variables; they will be synthesized automatically, too, and will have an _ prepended to their name to prevent accidental direct access).

With "atomic", the synthesized setter/getter will ensure that a whole value is always returned from the getter or set by the setter, regardless of setter activity on any other thread. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.

In nonatomic, no such guarantees are made. Thus, nonatomic is considerably faster than "atomic".

What "atomic" does not do is make any guarantees about thread safety. If thread A is calling the getter simultaneously with thread B and C calling the setter with different values, thread A may get any one of the three values returned -- the one prior to any setters being called or either of the values passed into the setters in B and C. Likewise, the object may end up with the value from B or C, no way to tell.

Ensuring data integrity -- one of the primary challenges of multi-threaded programming -- is achieved by other means.

Adding to this:

atomicity of a single property also cannot guarantee thread safety when multiple dependent properties are in play.

Consider:

 @property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;

In this case, thread A could be renaming the object by calling setFirstName: and then calling setLastName:. In the meantime, thread B may call fullName in between thread A's two calls and will receive the new first name coupled with the old last name.

To address this, you need a transactional model. I.e. some other kind of synchronization and/or exclusion that allows one to exclude access to fullName while the dependent properties are being updated.

Is reading a 64-bit atomic value safe on 64-bit platforms if I write/swap using OS atomic functions with barrier?

This OSAtomic API is deprecated. The documentation doesn’t mention it and you don’t see the warning from Swift, but used from Objective-C you will receive deprecation warnings:

'OSAtomicCompareAndSwap64Barrier' is deprecated: first deprecated in iOS 10 - Use atomic_compare_exchange_strong() from <stdatomic.h> instead

(If working on macOS, it warns you that it was deprecated in macOS 10.12.)

See How do I atomically increment a variable in Swift?


You asked:

The OSAtomic interface is deprecated now but I think any replacement would have more or less the same functionality and the same behaviour behind the scenes. So the question of whether 32-bit and 64-bit values can be read safely is still in place.

The suggested replacement is stdatomic.h. It has a atomic_load method, and I would use that rather than accessing directly.


Personally, I’d suggest you don’t use OSAtomic. From Objective-C you could consider using stdatomic.h, but from Swift I’d advise using one of the standard common synchronization mechanisms such as GCD serial queues, GCD reader-writer pattern, or NSLock based approaches. Conventional wisdom is that GCD was faster than locks, but all my recent benchmarks seem to suggest that the opposite is true now.

So I might suggest using locks:

class Synchronized<Value> {
private var _value: Value
private var lock = NSLock()

init(_ value: Value) {
self._value = value
}

var value: Value {
get { lock.synchronized { _value } }
set { lock.synchronized { _value = newValue } }
}

func synchronized<T>(block: (inout Value) throws -> T) rethrows -> T {
try lock.synchronized {
try block(&_value)
}
}
}

With this little extension (inspired by Apple’s withCriticalSection method) to provide simpler NSLock interaction:

extension NSLocking {
func synchronized<T>(block: () throws -> T) rethrows -> T {
lock()
defer { unlock() }
return try block()
}
}

Then, I can declare a synchronized integer:

let foo = Synchronized<Int>(0)

And now I can increment that a million times from multiple threads like so:

DispatchQueue.concurrentPerform(iterations: 1_000_000) { _ in
foo.synchronized { value in
value += 1
}
}

print(foo.value) // 1,000,000

Note, while I provide synchronized accessor methods for value, that’s only for simple loads and stores. I’m not using it here because we want the entire load, increment, and store to be synchronized as a single task. So I’m using the synchronized method. Consider the following:

DispatchQueue.concurrentPerform(iterations: 1_000_000) { _ in
foo.value += 1
}

print(foo.value) // not 1,000,000 !!!

It looks reasonable because it’s using synchronized value accessors. But it just doesn’t work because the synchronization logic is at the wrong level. Rather than synchronizing the load, the increment, and the store of this value individually, we really need all three steps to be synchronized all together. So we wrap the whole value += 1 within the synchronized closure, like shown in the previous example, and achieve the desired behavior.

By the way, see Use queue and semaphore for concurrency and property wrapper? for a few other implementations of this sort of synchronization mechanism, including GCD serial queues, GCD reader-writer, semaphores, etc., and a unit test that not only benchmarks these, but also illustrates that simple atomic accessor methods are not thread-safe.


If you really wanted to use stdatomic.h, you can implement that in Objective-C:

//  Atomic.h

@import Foundation;

NS_ASSUME_NONNULL_BEGIN

@interface AtomicInt: NSObject

@property (nonatomic) int value;

- (void)add:(int)value;

@end

NS_ASSUME_NONNULL_END

And

//  AtomicInt.m

#import "AtomicInt.h"
#import <stdatomic.h>

@interface AtomicInt()
{
atomic_int _value;
}
@end

@implementation AtomicInt

// getter

- (int)value {
return atomic_load(&_value);
}

// setter

- (void)setValue:(int)value {
atomic_store(&_value, value);
}

// add methods for whatever atomic operations you need

- (void)add:(int)value {
atomic_fetch_add(&_value, value);
}

@end

Then, in Swift, you can do things like:

let object = AtomicInt()

object.value = 0

DispatchQueue.concurrentPerform(iterations: 1_000_000) { _ in
object.add(1)
}

print(object.value) // 1,000,000

Clearly, you would add whatever atomic operations you need to your Objective-C code (I only implemented atomic_fetch_add, but hopefully it illustrates the idea).

Personally, I’d stick with more conventional Swift patterns, but if you really wanted to use the suggested replacement for OSAtomic, this is what an implementation could possibly look like.

Compare between 3 values and print final result

  1. This operation (KFinal > VFinal & AFinal) is wrong. It should be KFinal > VFinal && KFinal > AFinal
  2. Moved the last three operations to the top
var VFinal = 5
var AFinal = 5
var KFinal = 5

func finalResultText() {

if KFinal > VFinal && KFinal > AFinal {
print("Kinesthetic")
} else if AFinal > VFinal && AFinal > KFinal {
print("Auditive")
} else if VFinal > KFinal && VFinal > AFinal {
print("Visual")
} else if AFinal == VFinal && AFinal == KFinal {
print("Visual, Auditive and Kinesthetic")
} else if AFinal == VFinal {
print("Visual and Auditive")
} else if VFinal == KFinal {
print("Visual and Kinesthetic")
} else if KFinal == AFinal {
print("Auditive and Kinesthetic")
}
}

Using a pointer in Swift 3 to modify Data

A possible approach:

  • Read the file into a Data value.
  • Use withUnsafeMutableBytes() to mutate the bytes.
  • Create a UnsafeMutableBufferPointer, this allows to modify
    the data via subscripting instead of pointer arithmetic.
  • Write the data back to the file.
  • Use do/try/catch for error handling.

Example:

func modifyFile(filePath: String) {
let fileURL = URL(fileURLWithPath: filePath)
do {
var data = try Data(contentsOf: fileURL)
data.withUnsafeMutableBytes { (i16ptr: UnsafeMutablePointer<Int16>) in
let i16buffer = UnsafeMutableBufferPointer(start: i16ptr, count: data.count/MemoryLayout<Int16>.stride)

i16buffer[3] = 1234 // modify the 4th value
}
try data.write(to: fileURL, options: .atomic)
} catch let error {
print(error.localizedDescription)
}
}

what is the difference between strong and weak property?

Strong means that as long as this property points to an object, that object will not be automatically released. In non-ARC it's a synonym for retain.

Weak instead, means that the object the property points to, is free to release but only if it sets the property to nil. In ARC you use weak to ensure you do not own the object it points to.

Differences between strong and weak in Objective-C

A strong reference (which you will use in most cases) means that you want to "own" the object you are referencing with this property/variable. The compiler will take care that any object that you assign to this property will not be destroyed as long as you point to it with a strong reference. Only once you set the property to nil will the object get destroyed (unless one or more other objects also hold a strong reference to it).

In contrast, with a weak reference you signify that you don't want to have control over the object's lifetime. The object you are referencing weakly only lives on because at least one other object holds a strong reference to it. Once that is no longer the case, the object gets destroyed and your weak property will automatically get set to nil. The most frequent use cases of weak references in iOS are:

  1. delegate properties, which are often referenced weakly to avoid retain cycles, and

  2. subviews/controls of a view controller's main view because those views are already strongly held by the main view.

atomic vs. nonatomic refers to the thread safety of the getter and setter methods that the compiler synthesizes for the property. atomic (the default) tells the compiler to make the accessor methods thread-safe (by adding a lock before an ivar is accessed) and nonatomic does the opposite. The advantage of nonatomic is slightly higher performance. On iOS, Apple uses nonatomic for almost all their properties so the general advice is for you to do the same.

Objective-C ARC: strong vs retain and weak vs assign

From the Transitioning to ARC Release Notes (the example in the section on property attributes).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

So strong is the same as retain in a property declaration.

For ARC projects I would use strong instead of retain, I would use assign for C primitive properties and weak for weak references to Objective-C objects.



Related Topics



Leave a reply



Submit