class Counter {
var value = 0
private let lock = NSLock()
func increment() {
lock.lock()
value += 1
print("Value: \(value)")
lock.unlock()
}
func decrement() {
lock.lock()
value -= 1
print("Value: \(value)")
lock.unlock()
}
}
let counter = Counter()
let queue = DispatchQueue(label: "com.example.queue", attributes: .concurrent)
let group = DispatchGroup()
for _ in 0..<100 {
group.enter()
queue.async {
counter.increment()
group.leave()
}
group.enter()
queue.async {
counter.decrement()
group.leave()
}
}
group.notify(queue: .main) {
print(counter.value)
}
// 0
Counter
라는 클래스를 정의하고, increment()
와 decrement()
메서드를 사용하여 값을 증가시키거나 감소시킵니다. NSLock
클래스를 사용하여 Lock을 생성하고, lock()
메서드로 잠그고 unlock()
메서드로 잠금을 해제한다.increment()
와 decrement()
메서드가 동시에 호출되더라도 값의 증감이 올바르게 동작한다. Product
> Scheme
> Edit Scheme
을 선택한다.Run
을 선택하고, 오른쪽의 Diagnostics
탭으로 이동한다.Thread Sanitizer
체크박스를 활성화하고 Close
버튼을 클릭한다.private let threadSafeCountQueue = DispatchQueue(label: "...")
private var _count = 0
public var count: Int {
get {
return threadSafeCountQueue.sync {
_count
}
}
set {
threadSafeCountQueue.sync {
_count = newValue
}
}
}
threadSafeCountQueue
는 시리얼 큐이다.sync
의 의미는 "글로벌 디폴트큐"에서 "시리얼 큐"로 보낸 작업을 기다린다는 의미private let threadSafeCountQueue = DispatchQueue(label: "...", attributes: .concurrent)
private var _count = 0
public var count: Int {
get {
return threadSafeCountQueue.sync {
return _count
}
}
set {
threadSafeCountQueue.async(flags: .barrier) { [unowned self] in
self._count = newValue
}
}
}
class SharedInstanceClass {
lazy var testVar = {
return Int.random(in: 0..<99)
}()
}
let queue = DispatchQueue(label: "test", qos: .default, attributes: [.initiallyInactive, .concurrent], autoreleaseFrequency: .workItem, target: nil)
let group = DispatchGroup()
let instance = SharedInstanceClass()
for i in 0 ..< 10 {
group.enter()
queue.async(group: group, qos: .default) {
let id = i
print("\(id) \(instance.testVar)")
group.leave()
}
}
queue.activate()
group.wait()
class SharedInstanceClass2 {
let serialQueue = DispatchQueue(label: "serial")
lazy var testVar = {
return Int.random(in: 0...100)
}()
// 객체 내부에서 시리얼큐로 다시 testVar에 접근하도록
var readVar: Int {
serialQueue.sync {
return testVar
}
}
}
// 디스패치그룹 생성
let group2 = DispatchGroup()
// 객체 생성
let instance2 = SharedInstanceClass2()
// 실제 비동기 작업 실행
for i in 0 ..< 100 {
group2.enter()
queue.async(group: group2) {
print("id:\(i), lazy var 이슈:\(instance2.readVar)")
group2.leave()
}
}
group2.notify(queue: DispatchQueue.global()){
print("시리얼큐로 해결한 모든 작업의 완료.")
}
queue.activate()
group1.wait()
class SharedInstanceClass4 {
lazy var testVar = {
return Int.random(in: 0...100)
}()
}
// 디스패치그룹 생성
let group4 = DispatchGroup()
// 객체 생성
let instance4 = SharedInstanceClass4()
let semaphore = DispatchSemaphore(value: 1)
// 실제 비동기 작업 실행
for i in 0 ..< 100 {
group4.enter()
semaphore.wait()
queue.async(group: group4) {
print("id:\(i), lazy var 이슈:\(instance4.testVar)")
group4.leave()
semaphore.signal()
}
}
group4.notify(queue: DispatchQueue.global()){
print("디스패치 세마포어로 해결한 모든 작업의 완료.")
}
class SharedInstanceClass3 {
lazy var testVar = {
return Int.random(in: 0...100)
}()
}
// 디스패치그룹 생성
let group3 = DispatchGroup()
// 객체 생성
let instance3 = SharedInstanceClass3()
// 실제 비동기 작업 실행
for i in 0 ..< 100 {
group3.enter()
queue.async(flags: .barrier) {
print("id:\(i), lazy var 이슈:\(instance3.testVar)")
group3.leave()
}
}
group3.notify(queue: DispatchQueue.global()){
print("디스패치 배리어로 해결한 모든 작업의 완료.")
}
제가 학습한 내용을 요약하여 정리한 것입니다. 내용에 오류가 있을 수 있으며, 어떠한 피드백도 감사히 받겠습니다.
감사합니다.