스위프트 변수가 원자인가요?
Objective-C에서는 원자와 비원자의 특성을 구분할 수 있습니다.
@property (nonatomic, strong) NSObject *nonatomicObject;
@property (atomic, strong) NSObject *atomicObject;
여러 스레드에서 원자로 정의된 속성을 안전하게 읽고 쓸 수 있는 반면, 여러 스레드에서 원자로 정의되지 않은 속성이나 아이바를 동시에 쓰고 액세스하면 잘못된 액세스 오류를 포함하여 정의되지 않은 동작이 발생할 수 있습니다.
Swift에 이와 같은 변수가 있는 경우:
var object: NSObject
제가 이 변수를 안전하게 병렬로 읽고 쓸 수 있습니까? (이것을 하는 것의 실제 의미는 고려하지 않고)
낮은 수준의 문서가 없기 때문에 가정하기는 매우 이르지만, 조립부터 공부할 수 있습니다.호퍼 분해기는 훌륭한 도구입니다.
@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
스스로 실행하는 행동입니다.
스위프트는 실 안전에 관한 언어 구성이 없습니다.제공된 라이브러리를 사용하여 자체 스레드 안전 관리를 수행한다고 가정합니다.pthread mutex, NSLock 및 dispatch_sync를 뮤텍스 메커니즘으로 사용하는 등 스레드 안전을 구현하는 데 많은 옵션이 있습니다.이 주제에 대한 Mike Ash의 최근 게시물 참조: https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html 그렇다면 "이 변수를 안전하게 병렬로 읽고 쓸 수 있습니까?"라는 질문에 대한 직접적인 대답은 아니오입니다.
이 질문에 대답하기에는 아마도 이릅니다.현재 swift는 접근 수정자가 부족하여 속성 getter/setter 주변의 동시성을 관리하는 코드를 추가할 명확한 방법이 없습니다.게다가 스위프트 랭귀지는 아직 동시성에 대한 정보가 없는 것 같습니다! (KVO 등도 부족합니다.
이 질문에 대한 답은 앞으로 공개될 때 명확해질 것이라고 생각합니다.
세부 사항
- Xcode 9.1, 스위프트 4
- Xcode 10.2.1 (10E1001), Swift 5
링크스
- apple.developer.com 디스패치
- Swift 3의 GCD(Grand Central Dispatch) 및 디스패치 대기열
- Swift에서 스레드-세이프 어레이 만들기
- Swift에서 음소거 및 닫힘 캡처
구현형
- QueueSafeValue - 값에 대한 안전한 다중 스레드 액세스를 제공하는 범용 래퍼
- 원자 배열
- 아토믹 정수
- 원자 값
메인 아이디어
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()
결과
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
}
}
사용방법:
class Shared {
@atomic var value: Int
...
}
여기 제가 많이 사용하는 원자성 물품 포장지가 있습니다.실제 잠금 메커니즘을 프로토콜로 만들어 다양한 메커니즘으로 실험할 수 있었습니다.데,DispatchQueues
, .pthread_rwlock_t
.pthread_rwlock_t
오버헤드가 가장 낮고 우선 순위 반전 가능성이 낮기 때문에 선택했습니다.
/// Defines a basic signature that all locks will conform to. Provides the basis for atomic access to stuff.
protocol Lock {
init()
/// Lock a resource for writing. So only one thing can write, and nothing else can read or write.
func writeLock()
/// Lock a resource for reading. Other things can also lock for reading at the same time, but nothing else can write at that time.
func readLock()
/// Unlock a resource
func unlock()
}
final class PThreadRWLock: Lock {
private var rwLock = pthread_rwlock_t()
init() {
guard pthread_rwlock_init(&rwLock, nil) == 0 else {
preconditionFailure("Unable to initialize the lock")
}
}
deinit {
pthread_rwlock_destroy(&rwLock)
}
func writeLock() {
pthread_rwlock_wrlock(&rwLock)
}
func readLock() {
pthread_rwlock_rdlock(&rwLock)
}
func unlock() {
pthread_rwlock_unlock(&rwLock)
}
}
/// A property wrapper that ensures atomic access to a value. IE only one thing can write at a time.
/// Multiple things can potentially read at the same time, just not during a write.
/// By using `pthread` to do the locking, this safer then using a `DispatchQueue/barrier` as there isn't a chance
/// of priority inversion.
@propertyWrapper
public final class Atomic<Value> {
private var value: Value
private let lock: Lock = PThreadRWLock()
public init(wrappedValue value: Value) {
self.value = value
}
public var wrappedValue: Value {
get {
self.lock.readLock()
defer { self.lock.unlock() }
return self.value
}
set {
self.lock.writeLock()
self.value = newValue
self.lock.unlock()
}
}
/// Provides a closure that will be called synchronously. This closure will be passed in the current value
/// and it is free to modify it. Any modifications will be saved back to the original value.
/// No other reads/writes will be allowed between when the closure is called and it returns.
public func mutate(_ closure: (inout Value) -> Void) {
self.lock.writeLock()
closure(&value)
self.lock.unlock()
}
}
언급URL : https://stackoverflow.com/questions/24157834/are-swift-variables-atomic
'programing' 카테고리의 다른 글
C의 유사 제네릭 (0) | 2023.10.10 |
---|---|
Node.js를 확인하는 방법: "오류: ENOENT: 해당 파일 또는 디렉토리가 없습니다." (0) | 2023.10.10 |
Chrome 버전 58의 리액터 편집기 텍스트 형식 문제 (0) | 2023.10.10 |
PHP - 특정 배열 값 카운트 (0) | 2023.10.10 |
WooCommerce에서 사용자 정의 제품 유형에 대한 가격 및 재고 활성화 방법 (0) | 2023.10.10 |