Swift 변수는 원자 적입니까?
Objective-C에서는 원자 속성과 비 원자 속성을 구분합니다.
@property (nonatomic, strong) NSObject *nonatomicObject;
@property (atomic, strong) NSObject *atomicObject;
내 이해에 따르면 여러 스레드에서 원자로 정의 된 속성을 안전하게 읽고 쓸 수 있지만 동시에 여러 스레드에서 비 원자 속성 또는 ivar를 작성하고 액세스하면 잘못된 액세스 오류를 포함하여 정의되지 않은 동작이 발생할 수 있습니다.
따라서 Swift에 다음과 같은 변수가있는 경우 :
var object: NSObject
이 변수를 안전하게 읽고 쓸 수 있습니까? (이 작업의 실제 의미를 고려하지 않고).
저수준 문서를 사용할 수 없기 때문에 가정하는 것은 매우 이르지만 어셈블리에서 공부할 수 있습니다. Hopper Disassembler 는 훌륭한 도구입니다.
@interface ObjectiveCar : NSObject
@property (nonatomic, strong) id engine;
@property (atomic, strong) id driver;
@end
사용 objc_storeStrong
및 objc_setProperty_atomic
비 원자 및 원자에 대해 각각
class SwiftCar {
var engine : AnyObject?
init() {
}
}
에서 사용 swift_retain
하는 libswift_stdlib_core
것은 스레드 안전성이 내장되어 있지 않은 것 같습니다.
@lazy
나중에 추가 키워드 (와 유사한 )가 도입 될 수 있다고 추측 할 수 있습니다.
업데이트 07/20/15 : 싱글 톤 에 대한이 블로그 게시물에 따르면 신속한 환경은 특정 경우를 스레드로부터 안전하게 만들 수 있습니다.
class Car {
static let sharedCar: Car = Car() // will be called inside of dispatch_once
}
private let sharedCar: Car2 = Car2() // same here
class Car2 {
}
업데이트 05/25/16 : 신속한 진화 제안 https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md- 그대로 보입니다. @atomic
스스로 행동을 구현할 수 있습니다 .
Swift에는 스레드 안전성에 대한 언어 구조가 없습니다. 자체 스레드 안전 관리를 수행하기 위해 제공된 라이브러리를 사용한다고 가정합니다. pthread 뮤텍스, NSLock 및 뮤텍스 메커니즘으로 dispatch_sync를 포함하여 스레드 안전성을 구현하는 데는 많은 옵션이 있습니다. 주제에 대한 Mike Ash의 최근 게시물을 참조하십시오 : https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html 따라서 "Can 이 변수를 병렬로 안전하게 읽고 씁니까? " 아니오입니다.
이 질문에 답하기에는 이르다. 현재 swift에는 액세스 수정자가 없기 때문에 속성 getter / setter 주변의 동시성을 관리하는 코드를 추가하는 명확한 방법이 없습니다. 게다가 Swift Language는 아직 동시성에 대한 정보가없는 것 같습니다! (KVO 등도 부족합니다 ...)
이 질문에 대한 답은 향후 릴리스에서 분명해질 것이라고 생각합니다.
세부
- Xcode 9.1, Swift 4
- Xcode 10.2.1 (10E1001), Swift 5
연결
- apple.developer.com 디스패치
- Swift 3의 Grand Central Dispatch (GCD) 및 Dispatch Queues
- Swift에서 스레드로부터 안전한 배열 만들기
- Swift의 뮤텍스 및 클로저 캡처
구현 된 유형
주요 아이디어
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
}
}
}
원자 적 액세스 샘플
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()
}
}
}
}
용법
Atomic().semaphoreSample()
//Atomic().dispatchQueueSync()
//Atomic().objcSync()
결과
참고 URL : https://stackoverflow.com/questions/24157834/are-swift-variables-atomic
'Programming' 카테고리의 다른 글
대형 개체 힙 조각화 (0) | 2020.08.25 |
---|---|
R 스크립트 줄 번호 오류? (0) | 2020.08.25 |
Chrome 개발자 창에서 요청하는 경우 '보류 중'이란 무엇을 의미하나요? (0) | 2020.08.25 |
Android 스튜디오 프로젝트에 두 개의 build.gradle 파일이있는 이유는 무엇입니까? (0) | 2020.08.25 |
자바 스크립트를 사용하여 브라우저에서 TCP 소켓에 연결 (0) | 2020.08.25 |