las*_*sej 98 objective-c swift
在Objective-C中,您可以区分原子和非原子属性:
@property (nonatomic, strong) NSObject *nonatomicObject;
@property (atomic, strong) NSObject *atomicObject;
Run Code Online (Sandbox Code Playgroud)
根据我的理解,您可以安全地读取和写入从多个线程定义为原子的属性,而同时从多个线程编写和访问非原子属性或ivars可能导致未定义的行为,包括错误的访问错误.
所以如果你在Swift中有这样的变量:
var object: NSObject
Run Code Online (Sandbox Code Playgroud)
我可以安全地并行读取和写入此变量吗?(不考虑这样做的实际意义).
Sas*_*ats 51
现在假设没有低级文档可用,但您可以从汇编中学习.Hopper Disassembler是一个很棒的工具.
@interface ObjectiveCar : NSObject
@property (nonatomic, strong) id engine;
@property (atomic, strong) id driver;
@end
Run Code Online (Sandbox Code Playgroud)
分别用于objc_storeStrong和objc_setProperty_atomic非原子和原子,其中
class SwiftCar {
var engine : AnyObject?
init() {
}
}
Run Code Online (Sandbox Code Playgroud)
使用swift_retainfrom libswift_stdlib_core和,显然,没有内置的线程安全.
我们可以推测@lazy以后可能会引入其他关键字(类似).
2015年7月20日更新:根据这篇关于单身人士的博客文章, swift环境可以使某些案例线程安全,即:
class Car {
static let sharedCar: Car = Car() // will be called inside of dispatch_once
}
private let sharedCar: Car2 = Car2() // same here
class Car2 {
}
Run Code Online (Sandbox Code Playgroud)
更新05/25/16:密切关注快速进化建议https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md - 它看起来像是将有可能@atomic自己实施行为.
Goo*_*oug 11
Swift没有围绕线程安全的语言结构.假设您将使用提供的库来执行您自己的线程安全管理.在实现线程安全性方面有很多选项,包括pthread互斥锁,NSLock和dispatch_sync作为互斥机制.请参阅Mike Ash最近关于这个主题的帖子:https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html 所以直接回答你的问题"可以我安全地并行读写这个变量?" 没有.
可能要早点回答这个问题.目前swift缺少访问修饰符,因此没有明显的方法来添加管理属性getter/setter的并发性的代码.此外,Swift语言似乎没有关于并发性的任何信息!(它也缺少KVO等......)
我认为这个问题的答案将在未来的版本中变得清晰.
class Example {
private lazy var semaphore = DispatchSemaphore(value: 1)
func executeThreadSafeFunc1() {
// Lock access. Only first thread can execute code below.
// Other threads will wait until semaphore.signal() will execute
semaphore.wait()
// your code
semaphore.signal() // Unlock access
}
func executeThreadSafeFunc2() {
// Lock access. Only first thread can execute code below.
// Other threads will wait until semaphore.signal() will execute
semaphore.wait()
DispatchQueue.global(qos: .background).async {
// your code
self.semaphore.signal() // Unlock access
}
}
}
Run Code Online (Sandbox Code Playgroud)
class Atomic {
let dispatchGroup = DispatchGroup()
private var variable = 0
// Usage of semaphores
func semaphoreSample() {
// value: 1 - number of threads that have simultaneous access to the variable
let atomicSemaphore = DispatchSemaphore(value: 1)
variable = 0
runInSeveralQueues { dispatchQueue in
// Only (value) queqes can run operations betwen atomicSemaphore.wait() and atomicSemaphore.signal()
// Others queues await their turn
atomicSemaphore.wait() // Lock access until atomicSemaphore.signal()
self.variable += 1
print("\(dispatchQueue), value: \(self.variable)")
atomicSemaphore.signal() // Unlock access
}
notifyWhenDone {
atomicSemaphore.wait() // Lock access until atomicSemaphore.signal()
print("variable = \(self.variable)")
atomicSemaphore.signal() // Unlock access
}
}
// Usage of sync of DispatchQueue
func dispatchQueueSync() {
let atomicQueue = DispatchQueue(label: "dispatchQueueSync")
variable = 0
runInSeveralQueues { dispatchQueue in
// Only queqe can run this closure (atomicQueue.sync {...})
// Others queues await their turn
atomicQueue.sync {
self.variable += 1
print("\(dispatchQueue), value: \(self.variable)")
}
}
notifyWhenDone {
atomicQueue.sync {
print("variable = \(self.variable)")
}
}
}
// Usage of objc_sync_enter/objc_sync_exit
func objcSync() {
variable = 0
runInSeveralQueues { dispatchQueue in
// Only one queqe can run operations betwen objc_sync_enter(self) and objc_sync_exit(self)
// Others queues await their turn
objc_sync_enter(self) // Lock access until objc_sync_exit(self).
self.variable += 1
print("\(dispatchQueue), value: \(self.variable)")
objc_sync_exit(self) // Unlock access
}
notifyWhenDone {
objc_sync_enter(self) // Lock access until objc_sync_exit(self)
print("variable = \(self.variable)")
objc_sync_exit(self) // Unlock access
}
}
}
// Helpers
extension Atomic {
fileprivate func notifyWhenDone(closure: @escaping ()->()) {
dispatchGroup.notify(queue: .global(qos: .utility)) {
closure()
print("All work done")
}
}
fileprivate func runInSeveralQueues(closure: @escaping (DispatchQueue)->()) {
async(dispatch: .main, closure: closure)
async(dispatch: .global(qos: .userInitiated), closure: closure)
async(dispatch: .global(qos: .utility), closure: closure)
async(dispatch: .global(qos: .default), closure: closure)
async(dispatch: .global(qos: .userInteractive), closure: closure)
}
private func async(dispatch: DispatchQueue, closure: @escaping (DispatchQueue)->()) {
for _ in 0 ..< 100 {
dispatchGroup.enter()
dispatch.async {
let usec = Int(arc4random()) % 100_000
usleep(useconds_t(usec))
closure(dispatch)
self.dispatchGroup.leave()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Atomic().semaphoreSample()
//Atomic().dispatchQueueSync()
//Atomic().objcSync()
Run Code Online (Sandbox Code Playgroud)
从 Swift 5.1 开始,您可以使用属性包装器为您的属性制定特定逻辑。这是原子包装器实现:
@propertyWrapper
struct atomic<T> {
private var value: T
private let lock = NSLock()
init(wrappedValue value: T) {
self.value = value
}
var wrappedValue: T {
get { getValue() }
set { setValue(newValue: newValue) }
}
func getValue() -> T {
lock.lock()
defer { lock.unlock() }
return value
}
mutating func setValue(newValue: T) {
lock.lock()
defer { lock.unlock() }
value = newValue
}
}
Run Code Online (Sandbox Code Playgroud)
如何使用:
class Shared {
@atomic var value: Int
...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30077 次 |
| 最近记录: |