Thread

Threading Programming Guide


About Threaded Programming

수년동안 컴퓨터의 중심에 있는 단일 마이크로 프로세서의 속도에 의해 크게 제한 되었습니다. 개별 프로세서의 속도가 실제 한계에 도달하기 시작하자 멀티 코어설계로 전환하여 동시에 여러 작업을 수행할수 있는 기회를 제공했습니다.


What Are Threads?

스레드는 애플리케이션 내에서 여러 실행을 구현하는 비교적 간단한 방법 입니다. 시스템 수준에서 다른 프로그램의 요구에 각 프로그램의 실행 시간을 계산하여 나란히 실행됩니다.

각 프로그램 내부에는 하나 이상의 실행 스레드가 있으며 이는 동시에 또는 거의 동시적으로 다른 작업을 수행할수 있습니다. 실제로 시스템은 이러한 실행 스레드를 관리하고 코어에서 실행되도록 스케줄링합니다.


Alternatives To Threads

스레드는 성능 문제를 해결하기 위한 만병 통치약이 아닙니다. 스레드가 제공하는 이점과함께 잠재적인 문제가 있습니다.

스레드를 직접 만드는데 있어 한가지 문제는 코드에 불확실성(uncertainty)을 추가한다는 것입니다. 스레드는 동시성을 지원하는 애플리케이션의 상대적을 낮은 수준의 복잡한 방법입니다. 작성한 디자인의 의미를 완전히 이해하지 못하면 동기화 또는 타이밍 문제가 발생할수 있습니다. 미묘한 동작 변경에서 애플리케이션 충돌 및 데이터 손상까지 다양합니다.

고려해야할 또다른 요소를 스레드 또는 동시성의 필요 유무 입니다. 스레드는 메모리 소비, CPU 시간에 많은 양의 오버 헤드를 프로세스에 도입합니다. 이 오버헤드가 의도한 작업에 비해 크거나, 다른 옵션 선택의 기회비용이 클수 있다는걸 알수 있습니다.

다음은 스레드 대체 기술입니다.

  • Opertation objects: 일반적으로 두번째 스레드(Secondary thread)에서 실행되는는 작업에 대한 렙퍼 입니다. 이것은 스레드 관리 측면을 숨기고, 작업자체에 집중할수 있게 해줍니다.
  • Grand Central Dispatch(GCD): 스레드 관리가 아닌 수행해야 할 작업에 집중할수 있는 스레드의 또 다른 대안입니다. GCD는 수행하려는 작업을 정의하고 대기열에 추가합니다. 대기열은 적절한 스레드에서 작업 일정을 처리합니다. 작업 대기열은 스레드를 사용하여 직접 수행할수 있는 것보다 효율적으로 작업을 실행하기 위한 코어 수와 현재 로드를 고려합니다(GCD 똑똑하내..)
  • Idle-time Notification
  • Asynchronous functions: 시스템 인터페이스에는 자동 동시성을 제공하는 많은 비동기 함수가 포함됩니다.
  • Timers
  • Separate Processes

Threading Packages

스레드의 기본 구현 메커니즘은 Mach Threads 이지만 해당 레벨(Mach level)에서 작업하는 경우는 거의 없습니다. 대신 보통보다 편리한 POSIX API, 또는 POSIX 에서 파생된것을 사용합니다.

Mach 구현은 선점형 실행 모델과 스레드가 서로 독립적이 되도록 예약하는 기능을 포함하여 스레드의 기본 기능으로 제공합니다.

애플리케이션에서 사용할수 있는 스레딩 기술

  • Cocoa Threads: NSThread를 사용하여 스레드를 구현합니다.
  • POSIX Threads: C 기반 인터페이스를 제공합니다. Cocoa 애플리케이션을 작성하지 않는 경우, 스레드를 작성하는 최상의 선택입니ㅏㄷ.
  • Multiprocessing Services

Run Loops

실행 루프(Run Loops)은 스레드에서 비동기적으로 도착하는 이벤트를 관리하는데 사용되는 구조의 한 부분입니다. 실행 루프는 스레드에 대한 하나 이상의 이벤트 소스를 모니터링하여 일을 합니다. 이벤트가 도착하면 시스템은 스레드를 깨우고 이벤트를 실행 루프에 전달한 다음 이를 지정된 처리기에 전달합니다. 이벤트가 없고 처리 할 준비가 되면 실행 루프는 스레드를 절전 모드로 설정합니다.

생성한 스레드와 함게 실행 루프를 사용할 필요는 없지만, 이렇게하면 더 나은 환경을 제공할 수 있습니다. 실행 루프는 아무것도 할 필요가 없을때 스레드를 절전 모드로 전환하기 때문에 폴링(Polling)할 필요가 없기때문에 CPU 주기와 프로세서의 절전을 높여줍니다.

실행 루프는 폴링이 필요하지 않을때 잠자기 절전모드로 전환하기 때문에, 그것은 CPU cycle를 낭비하고, 프로세스의 전력 절약, 잠자기를 방해합니다.


Inter-thread Communication

좋은 설계가 필요한 통신의 양을 최소화 하더라도, 어떤 시점에서 스레드간의 통신이 필요하게 됩니다. 이러한 상황에서는 한 스레드에서 다른 스레드로 정보를 가져오는 방법이 필요합니다. 다행스럽게도 스레드가 동일한 프로세스 공간을 공유 한다는 사실은 통신 옵션이 많다는 것을 의미합니다.

아래는 소통 매커니즘입니다.

  • Direct messaging
  • Global variables, shared memory, and objects
  • Conditions
  • Run loop sources
  • Ports and sockets
  • Message queues
  • Cocoa distributed objec

Design Tips

  • Avoide Creating Threads Explicitly: 스레드 생성 코드를 수동으로 작성하는것은 잠재적 오류가 발생하기 쉽기 때문에 가능하면 이를 피하세요. OS X 와 iOs는 API를 통해 동시성을 암묵적으로 지원합니다. 스레드를 직접 작정하는 대신 비동기 API, GCD 또는 operation objects를 사용하세요
  • Keep Your Threads Reasonably busy: 수동으로 스레드를 만들고 관리하기로 결정한 경우 스레드가 중요한 시스템 리소스를 소비한다는걸 기억하세요. 스레드에 할당된 모든작업이 합리적이고 생산적인지 고민해야됩니다.

Thread를 종료하기전에 적절하게 해제 했는지 확인해야합니다. Thread를 종료할때 Thread에서 사용된 리소스들도 같이 정리된다는걸 보장하지 않습니다.

  • Thread and Your User Interface
  • Be Aware of Thread Behaviors at Quit Time
  • Handle Exceptions
  • Terminate Your Threads Cleanly: 스레드가 종료하는 가장 좋은 방법은 자연스럽게 작업을 종료하는 것입니다. 스레드를 즉시 종료하는 함수가 있지만 마지막 수단으로 생각해야합니다. 자연스럽게 끝에 도달하기 전에 스레드를 종료하면 스레드가 자체적으로 깨끗하게 정리되지 않습니다. 스레드가 메모리를 할당했거나, 파일을 열었거나, 다른 유형의 리소스를 얻은 경우 코드에서 해당 리소스를 회수하지 못하여 메모리 누수 또는 잠재적인 문제가 발생할수 있습니다.

비공식 예제

final class MainViewContorller: UIViewController {
    
    var thread: Thread = {
        let innerThread: Thread = Thread(target: self, selector: #selector(source), object: nil)
        
        return innerThread
    }()
    
    override func viewDidLoad() {
        
        // start thread... 
        thread.start()
        
    }
    
    @objc func source(){
        // do any..
    }
}

API Documnets


Reference

API Documnets
iOSHong님 블로그
iOSHong님 블로그