2017-12-30 78 views
1

NSKeyedArchiver을 사용하여 보관하려는 Set<CostumObject> 유형의 인스턴스가 있습니다.사용자 정의 개체 집합을 스레드로부터 안전하게 보관하는 방법은 무엇입니까?

customObject1: CostumObjectcustomObject2: CostumObject이 어딘가에 인스턴스화된다고 가정하십시오.

나는 다음과 같은 문을 사용하는 경우 :

let setOfCostomObjects: Set<CostumObject> = [customObject1, customObject2] 
let data = NSKeyedArchiver.archivedData(withRootObject: setOfCostomObjects) 

NSKeyedArchiver 아카이브 순차적으로 그 특성이 반복적으로 보관 모두 사용자 정의 개체를.

다른 스레드가 보관 중에 사용자 지정 개체와 해당 속성을 모두 변경할 수 있으므로 스레드로부터 안전하지 않습니다.

private let concurrentPropertyAccessQueue = DispatchQueue(label: "concurrentPropertyAccessQueue", attributes: .concurrent) 
… 
private var safeProperty = CostumProperty.init() 
public private(set) var property: CostumProperty { 
    get { 
    var result = CostumProperty.init() 
    concurrentPropertyAccessQueue.sync { result = safeProperty } // sync, because result is returned 
    return result 
    } // get 
    set { concurrentPropertyAccessQueue.async(flags: .barrier) { safeProperty = newValue } // executes locked after all gets 
    } // set 
} 
… 
public func threadSafeArchiveOfProperty() -> Data { 
    var data = Data.init() 
    concurrentPropertyAccessQueue.sync { // sync, because result is returned 
     data = NSKeyedArchiver.archivedData(withRootObject: self.safeProperty) 
    } 
    return data 
} 

:

은 내가 스레드 안전 할 수 아카이브를 사용자 정의 개체의 각 속성, 즉 동시 같은 세트에 대한 장벽으로 동시 큐를 사용하여 허용하지만, 단 하나의 세트된다됩니다 그렇게 생각 나는 또한 스레드 안전 할 수 아카이브를 전체 사용자 지정 개체를 비슷한 방법으로 생각 :

private let concurrentObjectAccessQueue = DispatchQueue(label: "concurrentObjectAccessQueue", attributes: .concurrent) 
… 
public func encode(with aCoder: NSCoder) { 
    concurrentObjectAccessQueue.async(execute: { 
     aCoder.encode(self.property forKey: "property") 
     … 
    }) 
} 

문제는 여전히 아카이브 사용자 정의 객체의 집합을 안전을 스레드하는 방법이다.
이렇게하면 아카이브하는 동안 집합 요소에 대한 쓰기 액세스가 잠길 수 있습니다. 하나는 아마 func threadSafeArchiveOfSet()를 정의하는 Set 유형의 확장을 쓸 수

public let globalConcurrentAccessQueue = DispatchQueue(label: "globalConcurrentAccessQueue", attributes: .concurrent) 

이 설정 및 보관 동안 모든 요소를 ​​잠 그려면 : 그렇게 할

한 가지 방법은 글로벌 동시 큐를 정의하는 아마 위와 같이.
이 함수는 globalConcurrentAccessQueue이 잠길 수 있도록 Set의 encode(with aCoder: NSCoder)을 덮어 씁니다.

이것이 올바른 방법인가요?
표준 해결책이 있어야하는 표준 문제라고 생각합니다.

+0

@Rob 빠른 답장을 보내 주셔서 감사합니다. 나는 그들을 이해해야하고, 다시 올 것이다. –

+0

@Rob 속성 수준 동기화에 관해서 : 당신은 완전히 옳았습니다 : 개체를 전체적으로 일관되게 유지하려면 개체 또는 개체의 모든 속성을 개체 수준에서 동기화해야하며 속성 수준의 동기화는 더 이상 사용되지 않습니다. 비동기 인코딩과 관련 : 당신은 다시 생각해 보았습니다. 호출자 인 NSKeyedArchiver는 모든 개별 아카이브 결과가 하나의 최종 데이터 객체에 결합되므로 인코딩이 순차적 프로세스라고 가정합니다. –

+0

@Rob 싱크 패턴의 단순화에 관해서 : 흥미 롭다! 나는 이것을 몰랐다. 제안이 작동하지만 [docs] (https://developer.apple.com/documentation/dispatch/dispatchqueue/1452870-sync)에서 찾을 수 없습니다. 동기화하지 말아야 반환 값이 있습니까? –

답변

0

종종 속성 수준 동기화가 단순히 부적절합니다. 개별 등록 정보에 대한 스레드 안전 액세스를 제공하지만, 다른 등록 정보 간의 상호 의존성이있을 수있는 더 넓은 오브젝트에 대한 스레드 안전 액세스를 보장하지는 않습니다. 프로토 타입 예제는 성과 속성을 가진 Person 개체입니다. 이름과성에 대한 동기화 변경 사항은 내부적으로 일관성없는 상태로 캡처되는 개체로 끝날 수 있습니다. 상위 수준에서 개체를 동기화해야하는 경우가 종종 있으며, 이렇게하면 속성 수준의 동기화가 중복됩니다.

몇 가지 관련이없는 관찰하십시오 encode 방법은 없습니다 asychronously, 기적의 작업을 수행해야합니다

  1. . 호출자는 인코딩이 반환 될 때까지 인코딩이 완료되었다고 가정합니다. 왜 비동기로 만들 수 있었는지 추측 할 수 있습니다 (예 : 명시 적으로 아무 것도 반환하지 않음). 그러나 문제는 반환되는 것이 아닌 오히려 더 광범위하게는 외부에서 부작용이 있는지 여부입니다. 동기화 된 개체.이 경우 NSCoder 개체를 업데이트하고 있으므로 encodesync을 사용해야합니다.

  2. 두 번 변수를 초기화하는 패턴을 사용하고 sync을 호출하여 해당 로컬 변수를 수정 한 다음 해당 값을 반환합니다. 예 :

    func threadSafeArchiveOfProperty() -> Data { 
        var data = Data.init() 
        concurrentPropertyAccessQueue.sync { // sync, because result is returned 
         data = NSKeyedArchiver.archivedData(withRootObject: self.safeProperty) 
        } 
        return data 
    } 
    

    그러나 sync가 폐쇄 값을 반환 즉 경우이를 단순화 할 수있는 좋은 방법을 제공 sync도 반환됩니다. 폐쇄가 하나 개의 라인을 가지고 있다면, 당신도 폐쇄에 명시 적 return 필요하지 않습니다 :

    func threadSafeArchiveOfProperty() -> Data { 
        return concurrentPropertyAccessQueue.sync { // sync, because result is returned 
         NSKeyedArchiver.archivedData(withRootObject: self.safeProperty) 
        } 
    } 
    
0

Basem에 마라가 here 세트에도 적용 할 수있는 스레드 안전 배열을위한 솔루션 설명 :

그는 일반 배열을 모방하기 위해 SynchronizedArray을 선언했습니다. 여기에는 개인 동시 대기열 및 배열이 포함되어 있으며 배열의 속성 및 메서드 중 일부가 노출되었습니다.
변경할 수없는 액세스는 동 기적으로 동시에 수행되는 반면, 변경 가능한 액세스는 장벽과 비동기 적으로 수행됩니다. 즉, 큐의 다른 모든 블록이 종료 된 후입니다.