RunLoop

kkh3·2022년 8월 27일
0
post-thumbnail

RunLoop란?

런루프는 thread와 관련있는 중요한 인프라 부분이다. 런루프는 이벤트 처리 loop로 작업을 스케쥴하거나 다가오는 이벤트를 조작하기위해서 사용한다.

런루프의 목적은 작업이 있을 경우 쓰레드를 바쁘게 유지하거나 해야할 작업이 없을 경우 쓰레드를 sleep하게 만들도록 한다.

런루프 관리는 전체가 자동으로 되어있지 않다. 적절한 시간에 런루프를 시작하기위해서 thread의 코드를 설계해야하고 다가오는 이벤트에 반응해야 한다.

Cocoa와 Core Foundation는 thread의 런루프를 만들고 관리하기 위해서 런루프 objects를 제공한다.

사용하는 application는 명확하게 이런 objects를 생성할 필요는 없다. 각 쓰레드, apllication의 메인쓰레드를 포함해서 관련 런루프 object를 가지고 있다. 오로지 2번째 쓰레드는 명확하게 이 런루프를 실행할 필요가 있다.

app 프레임워크는 application 시작 프로세스의 일부로서 메인 스레드에서 런루프를 자동적으로 설정하고 실행해한다.

공식문서를 보면 RunLoop는 아래와 같다.

  • The programmatic interface to objects that manage input sources.
class RunLoop : NSObject

런루프 객체는 window 시스템이나 Port 객체들로부터 마우스와 키보드 이벤트와 같은 것들의 input를 처리한다.

런루프 객체는 Timer events를 처리한다.

application에서 런루프 객체를 직접 생성하거나 관리하지 않는다.

이 시스템은 각 Thread 객체가 필요함에 따라 런루프 객체를 생성한다. 이는 application의 메인 스레드도 포함된다.

만약 현재 쓰레드의 런루프를 접근할 필요가 있다면 class method의 current를 사용해야 한다.

RunLoop에서 보면 Timer 객체는 입력이 아니다. 그래서 특수한 유형이며 실행 루프가 실행될 때 반환되지 않는다.

RunLoop 클래스는 thread-safe하지 않다. 그래서 현재 쓰레드의 context내에서 이 메서드를 호출해야한다.

다른 쓰레드에서 RunLoop 객체의 메서드를 호출하게 된다면 예상치 못한 결과가 나올 수 있다.

Run Loop의 구조

런루프는 들어오는 이벤트에 반응할 때 event handlers를 실행하기 위해서 사용한다.

코드에서 제어 상태를 제공하고 이는 런루프의 실제 반복 부분을 구현하기위해 사용한다. 다시 말하면 코드는 while for 반복을 제공해서 런루프를 돌린다.

반복내에서 설치된 handler를 부르거나 이벤트를 받기위한 이벤트 처리 코드를 실행하기 위해서 run loop objects를 사용한다.

런루프는 다른 두가지 타입의 소스로부터 이벤트를 받는다.

Input soruces는 비동기적 이벤트를 전달한다. 그래서 다른 쓰레드로나 다른 application로부터 메시지를 전달한다.

Timer sources는 동기적 이벤트를 전달한다. 그래서 스케쥴된 시간이나 반복되는 것을 일으킨다.

두 타입의 sources는 이벤트가 왔을 때 이벤트를 처리하기위해서 application-특정 handler 루틴을 사용한다.

그림에서는 런루프의 개념적 구조를 보여주고 각 source들을 보여주고 있다.

input soruces는 비동기적 이벤트르 전달해서 handler를 일치시키고 runUntilDate method를 호출해서 exit한다.

Timer source는 이벤트를 handler rountine로 전달하지만 런루프가 exit하도록 만들지않는다.

input의 sources를 다루기 위해서 런루프는 런루프의 행동에 대해 notification를 만든다.

등록된 runloop observers는 이러한 notifications들을 받고 스레드에서 추가적인 처리를 하기 위해서 사용한다.

다음 섹션에서는 이제 런루프의 구성요소와 런루프가 실행할 때의 mode에 대해 알아볼 것이다.

Run Loop Modes

런루프 모드는 input sources와 timer 모음과 notification를 받을 런루프의 observer들의 모임이다.

런루프를 지나가는 동안 오직 mode와 관련있는 sources가 감시되고 이벤트들에게 전달되기를 허락한다.

다른 modes와 관련있는 soruces들은 적절한 mode에서 루프를 통해 다음 pass가 올때까지 어떤 새 이벤트를 갖고있다.

코드에서 이름에 의해 modes를 구별한다.

Cocoa, Core Foundation 둘다 default mode와 여러 공통으로 사용되는 modes를 정의한다.

mode의 이름을 통해 커스텀 String를 지음으로써 커스텀 modes를 정의할 수 있다.

커스텀 모드를 할당하는 이름이 임의적이라도 이것들의 modes의 내부 내요은 임의적이지 않다.

하나 이상의 input sources, timers 혹은 런루프 observers를 내가 생성한 곳으로 더하도록 해야 유용하다.

런루프를 통한 각각의 pass 동안 원하지않는 소스들로부터 이벤트를 필터해서 modes를 사용한다.

대부분의 시간동안 시스템에서 정의된 default mode에서 런루프를 실행하기를 원할 것이다.

modal panel는 modal mode에서 실행될 것이다.

이 모드에서 오직 model panel과 관련된 sources들이 thread로 이벤트를 전달할 것이다.

보조 스레드는 시간이 중요한 operations동안 이벤트를 전달하 것으로부터 낮은 우선순위의 sources를 보호하기 위해서 커스텀 모드를 사용할 수 있다.

NOTE: 모드는 이벤트의 소스를 기반으로 구분하지 이벤트의 타입으로 구분하지 않는다.

아래 표는 Cocoa 및 Core Foundation에서 정의한 표준 mode와 해당 모드를 사용할 때에 대한 설명이다.

Input Sources

Input sources는 쓰레드들에 비동기로 이벤트를 전달한다.

일반적으로 이벤트의 soruce는 2개 중 하나의 input source의 타입에 따라 다르다.

Port-based input source는 application의 Mach ports를 감시한다.

커스텀 input sources는 커스텀 이벤트의 sources를 감시한다.

런루프가 관련되면 input source가 port-based인지 custom인지 상관없다.

시스템은 만약 2가지를 사용할 수 있다면 두개의 타입 중 input source를 전형적으로 실행한다.

두 source의 차이점은 각각이 어떻게 신호받는지만 다르다.

port-based sources는 kernel에 의해 자동적으로 신호를 받고, custom sources는 다른 쓰레드로부터 신호를 받아야 한다.

input source를 생성할 때 런루프의 하나이상의 mode에 할당해야한다.

Modes는 어떤 input sources가 주어진 순간에 감시되는지 영향을 끼친다.

대부분의 시간에 default mode에서 런루프를 실행한다. 하지만 커스텀 모드에서도 할 수 있다.

만약 input source가 현재 감시되는 모드가 아니라면 발생시키는 어떤 이벤트든 런루프가 정확한 모드를 실행하기 전까지 기다리고 있는다.

더 자세한 내용은 공식문서에서 보면 있다!

Timer Sources

Timer Source는 미래에 미리 설정된 시간에 동기로 스레드에 이벤트를 전달한다.

타이머는 스레드가 자신에게 무엇인가 하도록 알리는 방법이다.

예를 들면 search field(검색필드)에서 사용자의 연속적인 키 입력 사이에 일정시간이 지나면 자동 검색을 시작할 수 있도록 타이머를 사용한다.

이것은 time 관련 notification을 만들지만 timer는 실시간 메커니즘이 아니다.

input source처럼 timer는 런루프의 특정 모드와 관련있다.

만약 타이머가 런루프에 의해 감시되는 모드가 아니라면 Timer가 지원되는 모드 중 하나에서 runloop를 실행할 때까지 타이머가 실행되지 않는다.

유사하게 runloop가 handler routine를 실행하는 중간에는 타이머가 실행되면 타이머는 runloop를 통해 다음번에 handler routine를 호출할 때까지 기다려야 한다.

runloop가 실행되지 않으면 Timer도 실행되지 않는다.

이벤트를 한번이나 반본적으로 만들도록 Timer를 구현할 수 있다.

반복되는 타이머는 자동적으로 실제 실행 시간이 아닌 예약된 실행 시간에 따라 예약된다.

예를 들어, 타이머가 특정시간이나 매 5초마다 실행되도록 예약되면 예약된 실행 시간은 실제 실행시간이 지연되더라도 항상 원래 시간의 5초 간격으로 떨어져서 실행된다.

시작 시간이 너무 지연되어 예정된 시작 시간 중 하나 이상을 놓치면 놓친 시간동안에는 타이머가 한번만 실행된다.

놓친 기간 동안에 다시 실행된 후 타이머는 다음 예약된 실행시간으로 다시 예약된다.

언제 Run Loop를 사용할까?

보조 thread를 만들 때 런루프를 명시적으로 실행할 필요가 있다.

application의 main thread에서 런루프는 인프라의 중요한 부분이다.

결론적으로 app framework는 main application loop를 실행하거나 loop를 자동적으로 시작하느 코드를 제공한다.

iOS에서 UIApplication의 run method는 보통 시작 시점에 application의 메인 loop를 시작한다.

만약 Xcode template 프로젝트를 application를 만들기위해 사용한다면 이 routines를 명확하게 호출할 일이 없다.

보조 스레드에서는 런루프가 필요한지 여부를 결정해야한다. 만약 그렇다면 런루프를 만들고 시작해야한다.

모든 케이스에서 thread의 런루프를 시작할 필요는 없다.

예를 들어, 만약 오래 실행되거나 미리 결정해야하는 작업을 수행해야하는 thread를 사용하면 아마도 런루프를 시작하는 것을 피할 것이다.

런루프는 상호적으로 쓰레드와 함께 원하는 상황에서 보통 사용한다.

예를 들어, 만약 아래와 같은 것을 하려고 할때 런루프를 사용한다.

  • port 또는 custom input source 를 사용하여 다른 스레드와 통신해야 되는 경우
  • thread에서 Timer 를 사용해야 하는 경우
  • Cocoa Application에서 performSelector... 메서드를 사용해야 하는 경우
  • 주기적인 작업을 수행하기 위해 스레드를 유지해야 하는 경우

모든 스레드 프로그래밍과 마찬가지로 적절한 상황에서 보조 스레드를 종료할 계획을 가져야 한다. 스레드를 강제 종료하는것보다 종료하도록 하여 스레드를 깔끔하게 종료하는 것이 좋다

결론적으로 정리하자면 아래와 같다.

RunLoop에 대해 설명하시오

🔑 핵심 키워드

  • 작업 스케쥴링
  • 이벤트 처리 루프
  • Thread

📝 스크립트

  • 작업 스케쥴링과 전달된 이벤트를 처리하는 이벤트 처리 루프로써, Thread를 효율적으로 활용하기 위한 목적을 가지고 있는 객체입니다.

예상 질문

개발자가 직접 관리를 해주어야하나요?

🔑 핵심 키워드

  • Main Thread는 자동 실행
  • 그외 Thread는 수동 실행

📝 스크립트

  • Main Thread의 경우 Application이 시작될 때 프레임워크단에서 UIApplication 객체가 자동으로 RunLoop를 실행해주지만, 다른 Thread 의 경우 생성은 자동으로 되지만 만약 해당 Thread의 RunLoop를 사용해야 하는 경우엔 실행은 개발자가 직접 해주어야 합니다.

언제 RunLoop를 사용하게 되나요?

🔑 핵심 키워드

  • Thread 통신
  • 주기적인 작업 수행
  • Timer를 사용해야 하는 경우

📝 스크립트

  • Thread 사이의 통신을 해야하는 경우, 주기적인 작업을 계속해서 수행해야 하는 경우, Timer를 사용해야 하는 경우 주로 사용 됩니다. 하지만 Timer도 Main Thread에서 실행하는것이 안전하고 그 외 케이스들도 특수한 상황들이기 때문에 개발자가 직접 활용하는 케이스는 많지 않을 것 같습니다.

RunLoop의 mode는 무엇이 있으며 역할은 무엇일까요?

🔑 핵심 키워드

  • input mode
  • timer mode

📝 스크립트
input mode, timer mode가 있습니다.
Input sources는 쓰레드들에 비동기로 이벤트를 전달합니다.
Timer Source는 미래에 미리 설정된 시간에 동기로 스레드에 이벤트를 전달합니다.

Runloop는 thread-safe한가요?

🔑 핵심 키워드

  • class

📝 스크립트
RunLoop 클래스이기 떄문에 thread-safe하지 않습니다. 그래서 현재 쓰레드의 context내에서 이 메서드를 호출해야합니다.
다른 쓰레드에서 RunLoop 객체의 메서드를 호출하게 된다면 예상치 못한 결과가 나올 수 있습니다. 그러므로 사용에 주의해야합니다.

출처

profile
Make a better world

0개의 댓글