Swift Thread 사용해 보기

iOS 개발을 하면서 스레드를 직접 생성해서 해야하는 작업은 별로 없었다.
DispatchQueue, OperationQueue 를 이용해 대부분의 작업을 할 수 있지만
특정 하나의 스레드에서만 작업되기를 원한다면 스레드를 직접 생성해서 해당 스레드에서 작업이 되도록 해야 한다.

앱내에서 Realm 관련 작업을 했는데 해당 모델의 Read/Write 가 하나의 스레드에서 되어야 해서
특정 스레드를 생성해서 작업해야 했다.
다음은 스레드를 생성하고 작업대상을 추가하여 생성된 스레드에서만 작업이 되는 간단한 예시이다.

let t = CustomThread()
for i in 0 ..< 5 {
    t.push(Entry(index: i))
}

DispatchQueue.global().async {
    for i in 5 ..< 10 {
        t.push(Entry(index: i))
    }
}
// 스레드가 처리할 엔트리
class Entry {
    private var index = 0
    
    init(index: Int) {
        self.index = index
    }
    
    func work() {
        print("working, entry index \(index) thread \(Thread.current)")
    }
}

스레드가 처리할 엔트리를 넣을때와 실제 작업을 하기 위해 엔트리를 뺄 때
condition 객체를 이용하여 엔트리를 넣는 스레드와 엔트리를 빼는 스레드(CustomThread) 동시 접근을 막는다.

class CustomThread {
    private var serialQueue = DispatchQueue(label: "SerialQueue")
    private var thread: Thread!
    private var condition = NSCondition()
    private var entries = [Entry]()
  
    init() {
        thread = Thread(target: self, selector: #selector(self.main(_:)), object: nil)
        thread.start()
    }
  
    @objc
    func main(_ param: Any?) {
        while !Thread.current.isCancelled {
            condition.lock()
            if entries.isEmpty {
                condition.wait()
            }
      
            for entry in entries {
                entry.work()
            }
      
            entries.removeAll()
            condition.unlock()
        }
    }
  
    func push(_ entry: Entry) {
        func push() {
            condition.lock()
            entries.append(entry)
            condition.signal()
            condition.unlock()
        }
    
        serialQueue.async {
            push()
        }
    }
}

결과는 아래와 같다. 0~4 인덱스는 메인스레드에서 넣고 5~9 인덱스는 임의의 작업 스레드에서 넣었는데
실제 작업은 모두 하나의 스레드에서 한개씩 이루어 지는 것을 알 수 있다.

working, entry index 0 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 1 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 2 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 3 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 4 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 5 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 6 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 7 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 8 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}
working, entry index 9 thread <NSThread: 0x600000376ec0>{number = 7, name = (null)}

답글 남기기

이메일 주소는 공개되지 않습니다.