Intorduction | About Threaded Programming | Thread Management | Run Loops
Synchronization | Thread Safety Summary | Glossary

본 페이지는 Threading Programming Guide 문서의 Run Loops 부분을 번역해 놓은 페이지 입니다. 발 번역이라 이상한 부분이 있을 수 있습니다. 발견즉시 댓글을 달아 주세요.


Run Loops
루프를 실행

Run loops are part of the fundamental infrastructure associated with threads. A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread busy when there is work to do and put your thread to sleep when there is none.

실행 루프는 스레드와 관련된 기본적인 인프라의 일부입니다.런 루프는 작업을 예약하고 들어오는 이벤트의 영수증을 조정하는 데 사용되는 이벤트 처리 루프입니다.운전 루프의 목적은 아무도가 없을 때 잠자기 실을 넣어하는 작업이 때 스레드가 바쁜 유지하는 것입니다.

Run loop management is not entirely automatic. You must still design your thread’s code to start the run loop at appropriate times and respond to incoming events. Both Cocoa and Core Foundation provide run loop objects to help you configure and manage your thread’s run loop. Your application does not need to create these objects explicitly; each thread, including the application’s main thread, has an associated run loop object. Only secondary threads need to run their run loop explicitly, however. The app frameworks automatically set up and run the run loop on the main thread as part of the application startup process.

루프 관리는 완전히 자동으로되지 않습니다 실행합니다. 당신은 여전히 ​​적절한 시간에 실행 루프를 시작하고 들어오는 이벤트에 응답하기 위해 스레드의 코드를 설계해야합니다. 코코아 및 핵심 기초 모두 당신이 스레드의 실행 루프를 구성하고 관리 할 수 ​​있도록하기 위해 실행 루프 개체를 제공합니다. 응용 프로그램은 명시 적으로 이러한 개체를 만들 필요가 없습니다, ​​응용 프로그램의 주 스레드를 포함하여 각 스레드는 관련 실행 루프 개체가 있습니다. 만 보조 스레드는하지만, 명시 적으로 실행 루프를 실행해야합니다.응용 프로그램은 자동으로 설정하고 응용 프로그램 시작 프로세스의 일부로서 주 스레드에서 실행 루프를 실행 프레임 워크입니다.

The following sections provide more information about run loops and how you configure them for your application. For additional information about run loop objects, see NSRunLoop Class Reference and CFRunLoop Reference.

다음 섹션에서는 실행 루프에 대한 자세한 정보를 제공하고 당신은 응용 프로그램을 구성하는 방법. 런 루프 개체에 대한 자세한 내용은 NSRunLoop 클래스 참조 및 CFRunLoop 참조를 참조하십시오.

Anatomy of a Run Loop
운전 루프의 구조

A run loop is very much like its name sounds. It is a loop your thread enters and uses to run event handlers in response to incoming events. Your code provides the control statements used to implement the actual loop portion of the run loop—in other words, your code provides the while or for loop that drives the run loop. Within your loop, you use a run loop object to "run” the event-processing code that receives events and calls the installed handlers.

운전 루프의 이름의 소리와 매우 비슷하다. 그것은 당신의 스레드가 입력 루프 들어오는 이벤트에 대한 응답으로 이벤트 핸들러를 실행합니다. 코드는 실행의 실제 루프 부분을 구현하는 데 사용되는 제어 문을 제공 루프의 다른 단어 코드가 실행 루프를 구동하는 동안 또는 루프를 제공합니다. 귀하의 루프 내에서 이벤트를 수신하고 설치 핸들러를 호출하는 이벤트 처리 코드를 "실행"을 실행 루프 개체를 사용합니다.

A run loop receives events from two different types of sources. Input sources deliver asynchronous events, usually messages from another thread or from a different application. Timer sources deliver synchronous events, occurring at a scheduled time or repeating interval. Both types of source use an application-specific handler routine to process the event when it arrives.

런 루프 소스의 두 가지 유형의 이벤트를 수신합니다. 입력 소스가 비동기 이벤트를 다른 스레드에서 또는 다른 응용 프로그램에서 일반적으로 메시지를 전달합니다. 타이머 소스 동기 이벤트, 예약 된 시간에 발생하거나 간격을 반복을 제공합니다. 소스의 두 가지 유형은 도착 이벤트를 처리하는 응용 프로그램 별 처리기 루틴을 사용합니다.

Figure 3-1 shows the conceptual structure of a run loop and a variety of sources. The input sources deliver asynchronous events to the corresponding handlers and cause the runUntilDate: method (called on the thread’s associated NSRunLoop object) to exit. Timer sources deliver events to their handler routines but do not cause the run loop to exit.

그림 3-1은 실행 루프와 다양한 소스의 개념 구조를 보여줍니다.입력 소스는 해당 처리기에 대한 비동기 이벤트를 제공하고 runUntilDate 원인 : 종료 방법 (스레드의 관련 NSRunLoop 개체에서 호출). 타이머 소스는 핸들러 루틴에 이벤트를 전달하지만, 종료 실행 루프가 발생하지 않습니다.

Figure 3-1  Structure of a run loop and its sources
Structure of a run loop and its sources

In addition to handling sources of input, run loops also generate notifications about the run loop’s behavior. Registered run-loop observers can receive these notifications and use them to do additional processing on the thread. You use Core Foundation to install run-loop observers on your threads.

입력 소스를 처리 할뿐만 아니라, 실행은 실행 된 루프의 동작에 대한 알림을 생성 루프. 등록 런 루프 관찰자는 이러한 알림을 수신 스레드에서 추가 처리를 수행하는 데 사용할 수 있습니다. 당신은 당신의 스레드에서 실행 루프 관찰자를 설치하는 코어 파운데이션을 사용합니다.

The following sections provide more information about the components of a run loop and the modes in which they operate. They also describe the notifications that are generated at different times during the handling of events.

다음 섹션에서는 실행 루프의 구성 요소들이 작동하는 모드에 대한 자세한 정보를 제공합니다. 또한 이벤트를 처리하는 동안 다른 시간에 생성되는 알림을 설명합니다.

Run Loop Modes

루프 모드를 실행

run loop mode is a collection of input sources and timers to be monitored and a collection of run loop observers to be notified. Each time you run your run loop, you specify (either explicitly or implicitly) a particular “mode” in which to run. During that pass of the run loop, only sources associated with that mode are monitored and allowed to deliver their events. (Similarly, only observers associated with that mode are notified of the run loop’s progress.) Sources associated with other modes hold on to any new events until subsequent passes through the loop in the appropriate mode.

운전 루프 모드를 모니터 할 입력 소스 및 타이머의 수집 및 통보 할 런 루프 관찰자의 모음입니다. 당신이 실행 된 루프를 실행할 때마다, 당신은 (명시 적으로 또는 암시 적으로)를 실행하기 위해 특정 "모드"를 지정합니다.운전 루프의 단계에서, 그 모드 만 연결 소스 모니터링과 이벤트를 제공 할 수 있습니다. (마찬가지로,이 모드 만 연결 관찰자가 실행 된 루프의 진행 상황을 통보합니다.) 다른 모드와 관련된 소스는 해당 모드에서 루프를 연속 통과 할 때까지 모든 새 이벤트에 개최.

In your code, you identify modes by name. Both Cocoa and Core Foundation define a default mode and several commonly used modes, along with strings for specifying those modes in your code. You can define custom modes by simply specifying a custom string for the mode name. Although the names you assign to custom modes are arbitrary, the contents of those modes are not. You must be sure to add one or more input sources, timers, or run-loop observers to any modes you create for them to be useful.

코드에서, 당신은 이름 모드를 식별합니다. 코코아 및 핵심 기초 모두 코드에서 이러한 모드를 지정하는 문자열과 함께 기본 모드와 몇 가지 일반적으로 사용되는 모드를 정의합니다. 당신은 단순히 모드 이름에 대한 사용자 지정 문자열을 지정하여 사용자 지정 모드를 정의 할 수 있습니다. 사용자 정의 모드에 할당 이름은 임의이지만, 그 모드의 내용이 없습니다. 당신은 그들이 유용 할 당신이 만드는 모든 모드에 하나 이상의 입력 소스, 타이머, 또는 런타임 루프 관찰자를 추가해야합니다.

You use modes to filter out events from unwanted sources during a particular pass through your run loop. Most of the time, you will want to run your run loop in the system-defined “default” mode. A modal panel, however, might run in the “modal” mode. While in this mode, only sources relevant to the modal panel would deliver events to the thread. For secondary threads, you might use custom modes to prevent low-priority sources from delivering events during time-critical operations.

당신은 실행 루프를 통해 특정 단계에서 원하지 않는 소스에서 이벤트를 필터링 모드를 사용합니다. 시간의 대부분은, 당신이 시스템에 정의 된 "기본"모드에서 실행 된 루프를 실행하는 것이 좋습니다.모달 패널은, 그러나, "모달"모드에서 실행할 수 있습니다. 이 모드에서, 모달 패널에만 관련 소스는 스레드에 이벤트를 전달합니다. 보조 스레드를 들어, 시간이 중요한 작업 중에 이벤트를 전달에서 우선 순위가 낮은 소스를 방지하기 위해 사용자 정의 모드를 사용할 수 있습니다.

Table 3-1 lists the standard modes defined by Cocoa and Core Foundation along with a description of when you use that mode. The name column lists the actual constants you use to specify the mode in your code.

표 3-1에서는이 모드를 사용하는 경우에 대한 설명과 함께 코코아와 코어 재단에 의해 정의 된 표준 모드를 나열합니다.이름 열에는 코드에서 모드를 지정하는 데 사용하는 실제 상수를 나열합니다.

Table 3-1  Predefined run loop modes

Mode

Name

Description

Default

NSDefaultRunLoopMode(Cocoa)

kCFRunLoopDefaultMode (Core Foundation)

The default mode is the one used for most operations. Most of the time, you should use this mode to start your run loop and configure your input sources.

기본 모드는 대부분의 작업에 사용되는 하나입니다. 대부분의 시간, 당신은 당신의 런 루프를 시작하고 입력 소스를 구성하려면이 모드를 사용합니다.

Connection

NSConnectionReplyMode(Cocoa)

Cocoa uses this mode in conjunction with NSConnection objects to monitor replies. You should rarely need to use this mode yourself.

코코아 응답을 모니터링 할 NSConnection 개체와 함께이 모드를 사용합니다. 당신은 거의이 모드를 직접 사용할 필요가 없어야합니다.

Modal

NSModalPanelRunLoopMode(Cocoa)

Cocoa uses this mode to identify events intended for modal panels.

코코아 모달 패널을위한 이벤트를 식별하기 위해이 모드를 사용합니다.

Event tracking

NSEventTrackingRunLoopMode(Cocoa)

Cocoa uses this mode to restrict incoming events during mouse-dragging loops and other sorts of user interface tracking loops.

코코아 마우스 드래그 루프 및 사용자 인터페이스 추적 루프의 다른 종류의 동안 들어오는 이벤트를 제한하기 위해이 모드를 사용합니다.

Common modes

NSRunLoopCommonModes(Cocoa)

kCFRunLoopCommonModes (Core Foundation)

This is a configurable group of commonly used modes. Associating an input source with this mode also associates it with each of the modes in the group. For Cocoa applications, this set includes the default, modal, and event tracking modes by default. Core Foundation includes just the default mode initially. You can add custom modes to the set using the CFRunLoopAddCommonMode function.

이것은 일반적으로 사용되는 모드의 설정 그룹입니다. 그 그룹에있는 각 모드와도 연관이 모드로 입력 소스를 연결. 코코아 응용 프로그램의 경우,이 설정은 기본적으로 모달, 기본적으로 이벤트 추적 모드를 포함하고 있습니다. 핵심 재단은 당초 기본 모드를 포함합니다. 당신은 CFRunLoopAddCommonMode 함수를 사용하여 집합에 사용자 정의 모드를 추가 할 수 있습니다.

Input Sources

입력 소스

Input sources deliver events asynchronously to your threads. The source of the event depends on the type of the input source, which is generally one of two categories. Port-based input sources monitor your application’s Mach ports. Custom input sources monitor custom sources of events. As far as your run loop is concerned, it should not matter whether an input source is port-based or custom. The system typically implements input sources of both types that you can use as is. The only difference between the two sources is how they are signaled. Port-based sources are signaled automatically by the kernel, and custom sources must be signaled manually from another thread.

입력 소스는 스레드 비동기 이벤트를 제공합니다. 이벤트의 소스는 일반적으로 두 가지 범주 중 하나입니다 입력 소스의 종류에 따라 다릅니다. 포트 기반 입력 소스는 응용 프로그램의 마하 포트를 모니터링 할 수 있습니다. 사용자 정의 입력 소스는 이벤트의 사용자 정의 소스를 모니터링 할 수 있습니다. 지금까지의 실행 루프에 관한 한, 그것은 입력 소스가 포트 기반 또는 사용자 지정인지는 중요하지한다. 이 시스템은 일반적으로 사용할 수있는 두 가지 유형의 입력 소스를 구현합니다.두 소스 사이의 유일한 차이점은이 신호를하는 방법이다. 포트 기반 소스는 커널에 의해 자동으로 신호하는, 사용자 정의 소스는 다른 스레드에서 수동으로 신호를해야합니다.

When you create an input source, you assign it to one or more modes of your run loop. Modes affect which input sources are monitored at any given moment. Most of the time, you run the run loop in the default mode, but you can specify custom modes too. If an input source is not in the currently monitored mode, any events it generates are held until the run loop runs in the correct mode.

당신이 입력 소스를 만들 때, 당신은 당신의 운전 루프에 하나 이상의 모드에 할당합니다. 모드는 입력 소스가 어떤 주어진 순간에 모니터링되는 영향을 미칩니다. 대부분의 시간, 당신은 기본 모드에서 실행 루프를 실행,하지만 당신은 사용자 정의 모드를 지정할 수 있습니다.입력 소스가 현재 모니터 모드에 있지 않으면 실행 루프가 올바른 모드에서 실행까지가 생성하는 이벤트가 개최됩니다.

The following sections describe some of the input sources.

다음 섹션은 입력 소스의 일부를 설명합니다.

Port-Based Sources

포트 기반 소스

Cocoa and Core Foundation provide built-in support for creating port-based input sources using port-related objects and functions. For example, in Cocoa, you never have to create an input source directly at all. You simply create a port object and use the methods of NSPort to add that port to the run loop. The port object handles the creation and configuration of the needed input source for you.

코코아와 코어 재단은 포트 관련 개체와 함수를 사용하여 포트 기반 입력 소스를 만드는 기본적으로 지원합니다. 예를 들어, 코코아, 직접 모두에서 입력 소스를 만들 필요가 없습니다. 당신은 단순히 포트 개체를 만들고 실행 루프에 해당 포트를 추가 할 수 NSPort의 방법을 사용합니다.포트 개체는 당신을 위해 필요한 입력 소스의 생성 및 구성을 처리합니다.

In Core Foundation, you must manually create both the port and its run loop source. In both cases, you use the functions associated with the port opaque type (CFMachPortRefCFMessagePortRef, or CFSocketRef) to create the appropriate objects.

코어 재단에서 수동으로 포트 및 실행 루프 소스를 모두 작성해야합니다. 두 경우 모두 해당 개체를 만들 수있는 포트 불투명 타입 (CFMachPortRef, CFMessagePortRef 또는 CFSocketRef)와 연관된 함수를 사용합니다.

For examples of how to set up and configure custom port-based sources, see “Configuring a Port-Based Input Source.”

사용자 정의 포트 기반 소스를 설정 및 구성하는 방법의 예를 들어, "포트 기반 입력 소스 구성"을 참조하십시오.

Custom Input Sources

사용자 정의 입력 소스

To create a custom input source, you must use the functions associated with the CFRunLoopSourceRef opaque type in Core Foundation. You configure a custom input source using several callback functions. Core Foundation calls these functions at different points to configure the source, handle any incoming events, and tear down the source when it is removed from the run loop.

사용자 정의 입력 소스를 만들려면, 당신은 핵심 재단 CFRunLoopSourceRef 불투명 유형과 관련된 기능을 사용해야합니다. 당신은 몇 가지 콜백 함수를 사용하여 사용자 정의 입력 소스를 구성합니다. 핵심 재단은 소스를 구성 들어오는 이벤트를 처리하고 그것을 실행 루프에서 제거 될 때 원인을 찢어 다른 지점에서이 함수를 호출합니다.

In addition to defining the behavior of the custom source when an event arrives, you must also define the event delivery mechanism. This part of the source runs on a separate thread and is responsible for providing the input source with its data and for signaling it when that data is ready for processing. The event delivery mechanism is up to you but need not be overly complex.

이벤트가 도착하면 사용자 지정 원본의 동작을 정의하는 것 외에도, 당신은 또한 이벤트 전달 메커니즘을 정의해야합니다. 소스의이 부분은 별도의 스레드에서 실행하고 데이터를 입력 소스를 제공하고 데이터를 처리하기위한 준비가되었을 때 그것을 신호에 대한 책임이 있습니다.이벤트 전달 메커니즘은 당신에게 달려 있지만 지나치게 복잡 할 필요가 없습니다.

For an example of how to create a custom input source, see “Defining a Custom Input Source.” For reference information for custom input sources, see alsoCFRunLoopSource Reference.

사용자 정의 입력 소스를 만드는 방법에 대한 예를 들어, "사용자 정의 입력 소스 정의"을 참조하십시오. 사용자 정의 입력 소스에 대한 참조 정보 alsoCFRunLoopSource 참조를 참조하십시오.

Cocoa Perform Selector Sources

코코아 선택기 소스를 수행

In addition to port-based sources, Cocoa defines a custom input source that allows you to perform a selector on any thread. Like a port-based source, perform selector requests are serialized on the target thread, alleviating many of the synchronization problems that might occur with multiple methods being run on one thread. Unlike a port-based source, a perform selector source removes itself from the run loop after it performs its selector.

포트 기반 소스뿐만 아니라, 코코아는 모든 스레드에서 선택을 수행 할 수 있도록 사용자 정의 입력 소스를 정의합니다.포트 기반 소스처럼 선택 요청을 여러 방법이 하나의 스레드에서 실행중인 발생할 수있는 동기화 문제의 많은 것을 완화 대상 스레드에 직렬화 수행합니다.포트 기반 소스는 달리, 그것이 그 선택을 수행 한 후 선택 소스가 실행 루프에서 자신을 제거 수행합니다.

When performing a selector on another thread, the target thread must have an active run loop. For threads you create, this means waiting until your code explicitly starts the run loop. Because the main thread starts its own run loop, however, you can begin issuing calls on that thread as soon as the application calls theapplicationDidFinishLaunching: method of the application delegate. The run loop processes all queued perform selector calls each time through the loop, rather than processing one during each loop iteration.

다른 스레드에서 선택을 수행 할 때 대상 스레드가 활성 실행 루프를 가지고 있어야합니다. 당신이 만들고 스레드를 들어,이 코드를 명시 적으로 실행 루프를 시작할 때까지 기다리는 것을 의미합니다. 응용 프로그램 대리자 방법 : 주 스레드가 자신의 실행 루프를 시작하기 때문에 응용 프로그램이 theapplicationDidFinishLaunching 호출로, 그러나, 당신은 곧 스레드에서 호출을 실행을 시작할 수 있습니다.런 루프는 큐에 대기중인 모든 선택기 오히려 각 루프 반복하는 동안 하나를 처리하는 것보다, 루프를 통해 매번 호출을 수행 처리합니다.

Table 3-2 lists the methods defined on NSObject that can be used to perform selectors on other threads. Because these methods are declared on NSObject, you can use them from any threads where you have access to Objective-C objects, including POSIX threads. These methods do not actually create a new thread to perform the selector.

표 3-2는 다른 스레드에서 선택기를 수행하는 데 사용할 수 있습니다 NSObject의에 정의 된 메서드를 보여줍니다. 이러한 방법은 NSObject의에서 선언되어 있기 때문에, 당신은 당신이 POSIX 스레드를 포함하여 오브젝티브-C 객체에 대한 액세스 권한이있는 모든 스레드에서 사용할 수 있습니다. 이러한 방법은 실제로 선택기를 수행하기 위해 새로운 스레드를 생성하지 않습니다.

Table 3-2  Performing selectors on other threads

Methods

Description

performSelectorOnMainThread:withObject:waitUntilDone:

performSelectorOnMainThread:withObject:waitUntilDone:modes:

Performs the specified selector on the application’s main thread during that thread’s next run loop cycle. These methods give you the option of blocking the current thread until the selector is performed.

해당 스레드의 다음 실행 루프 사이클 동안 응용 프로그램의 주 스레드에서 지정된 셀렉터를 수행합니다. 이 방법은 당신에게 선택이 수행 될 때까지 현재 스레드를 차단하는 옵션을 제공합니다.

performSelector:onThread:withObject:waitUntilDone:

performSelector:onThread:withObject:waitUntilDone:modes:

Performs the specified selector on any thread for which you have an NSThreadobject. These methods give you the option of blocking the current thread until the selector is performed.

당신이 NSThreadobject을 가지고있는 모든 스레드에서 지정된 셀렉터를 수행합니다. 이 방법은 당신에게 선택이 수행 될 때까지 현재 스레드를 차단하는 옵션을 제공합니다.

performSelector:withObject:afterDelay:

performSelector:withObject:afterDelay:inModes:

Performs the specified selector on the current thread during the next run loop cycle and after an optional delay period. Because it waits until the next run loop cycle to perform the selector, these methods provide an automatic mini delay from the currently executing code. Multiple queued selectors are performed one after another in the order they were queued.

다음 실행 루프 사이클 동안 및 선택적 지연 기간 후에 현재 스레드의 지정된 셀렉터를 수행합니다.다음 실행 루프 사이클이 선택을 수행 할 때까지 대기하기 때문에이 방법은 현재 실행중인 코드에서 자동 미니 지연을 제공합니다. 여러 대기 선택기들이 대기 된 순서대로 잇달아 수행됩니다.

cancelPreviousPerformRequestsWithTarget:

cancelPreviousPerformRequestsWithTarget:selector:object:

Lets you cancel a message sent to the current thread using theperformSelector:withObject:afterDelay: orperformSelector:withObject:afterDelay:inModes: method.

withObject : afterDelay : orperformSelector : withObject : afterDelay : inModes 방법 : 당신이 theperformSelector을 사용하여 현재 스레드에 보낸 메시지를 취소 할 수 있습니다.

For detailed information about each of these methods, see NSObject Class Reference.
이러한 각 방법에 대한 자세한 내용은 NSObject의 클래스 참조를 참조하십시오.

Timer Sources

타이머 소스

Timer sources deliver events synchronously to your threads at a preset time in the future. Timers are a way for a thread to notify itself to do something. For example, a search field could use a timer to initiate an automatic search once a certain amount of time has passed between successive key strokes from the user. The use of this delay time gives the user a chance to type as much of the desired search string as possible before beginning the search.

타이머 소스는 미래의 지정된 시간에 당신의 스레드에 이벤트를 동 기적으로 제공합니다. 타이머 뭔가를 자체를 통지하는 스레드에 대한 방법입니다. 예를 들어, 검색 필드는 특정 시간에 사용자로부터 연속적인 키 입력 사이에 전달되면 자동으로 검색을 시작하는 타이머를 사용할 수 있습니다. 이 지연 시간의 사용은 사용자에게 검색을 시작하기 전에 가능한 한 원하는 검색 문자열만큼 입력 할 수있는 기회를 제공합니다.

Although it generates time-based notifications, a timer is not a real-time mechanism. Like input sources, timers are associated with specific modes of your run loop. If a timer is not in the mode currently being monitored by the run loop, it does not fire until you run the run loop in one of the timer’s supported modes. Similarly, if a timer fires when the run loop is in the middle of executing a handler routine, the timer waits until the next time through the run loop to invoke its handler routine. If the run loop is not running at all, the timer never fires.

이 시간 기반 알림을 생성하지만, 타이머 실시간 메커니즘 없습니다. 입력 소스와 마찬가지로, 타이머는 실행 루프의 특정 형태와 연관되어 있습니다.타이머가 현재 실행 루프에 의해 감시되는 모드에 있지 않은 경우에는 타이머의 지원되는 모드 중 하나를 실행 루프를 실행 할 때까지 발생하지 않습니다.런 루프가 핸들러 루틴을 실행하는 중간에있을 때 타이머가 발생하는 경우 마찬가지로 타이머 핸들러 루틴을 호출하는 실행 루프를 할 때까지 기다립니다.런 루프가 전혀 실행되지 않는 경우, 타이머가 발생하지 않습니다.

You can configure timers to generate events only once or repeatedly. A repeating timer reschedules itself automatically based on the scheduled firing time, not the actual firing time. For example, if a timer is scheduled to fire at a particular time and every 5 seconds after that, the scheduled firing time will always fall on the original 5 second time intervals, even if the actual firing time gets delayed. If the firing time is delayed so much that it misses one or more of the scheduled firing times, the timer is fired only once for the missed time period. After firing for the missed period, the timer is rescheduled for the next scheduled firing time.

당신은 한 번 또는 반복적으로 이벤트를 생성하기 위해 타이머를 구성 할 수 있습니다. 자동 예약 된 소성 시간이 아니라 실제 발사 시간에 따라 반복 타이머를 재조정 자체.타이머가 그 후 특정 시간 5 초에 발사 할 예정이다 예를 들어, 예약 된 소성 시간은 항상 실제 소성 시간이 지연되는 경우에도 원래의 시간은 5 초 간격에 떨어질 것이다.발사 시간이 너무 많이 예약 된 발사 시간 중 하나 이상을 그리워하는 지연되면 타이머가 누락 된 기간 동안 한 번만 발생합니다. 부재 기간 동안 소성 후, 타이머는 다음 예약 발사 시간을 재조정합니다.

For more information on configuring timer sources, see “Configuring Timer Sources.” For reference information, see NSTimer Class Reference or CFRunLoopTimer Reference.

타이머 소스를 구성하는 방법에 대한 자세한 내용은 "타이머 소스 구성"을 참조하십시오. 참조 정보 NSTimer 클래스 참조 또는 CFRunLoopTimer 참조를 참조하십시오.

Run Loop Observers

루프 관찰자를 실행

In contrast to sources, which fire when an appropriate asynchronous or synchronous event occurs, run loop observers fire at special locations during the execution of the run loop itself. You might use run loop observers to prepare your thread to process a given event or to prepare the thread before it goes to sleep. You can associate run loop observers with the following events in your run loop:

적절한 비동기 또는 동기 이벤트가 발생하면 불 런 루프 자체의 실행 중에 특별한 위치에 루프 관찰자 화재를 실행하는 소스는 달리. 당신은 지정된 이벤트를 처리하는거나 절전 모드로 전환되기 전에 스레드를 준비하기 위해 스레드를 준비하기 위해 실행 루프 관찰자를 사용할 수 있습니다. 당신은 실행 루프에서 다음과 같은 이벤트를 실행 루프 관찰자를 연결할 수 있습니다 :

  • The entrance to the run loop.
    운전 루프의 입구.

  • When the run loop is about to process a timer.
    런 루프는 타이머를 처리하기에 관하여됩니다.

  • When the run loop is about to process an input source.
    운전 루프에 입력 소스를 처리하기에 관하여됩니다.

  • When the run loop is about to go to sleep.
    런 루프가 잠을 잘려고 할 때.

  • When the run loop has woken up, but before it has processed the event that woke it up.
    런 루프는 깨어있다, 그러나 그것을 깨어 이벤트를 처리하기 전에합니다.

  • The exit from the run loop.
    실행 루프에서 종료합니다.

You can add run loop observers to apps using Core Foundation. To create a run loop observer, you create a new instance of the CFRunLoopObserverRef opaque type. This type keeps track of your custom callback function and the activities in which it is interested.

당신은 코어 파운데이션을 사용하여 응용 프로그램을 실행하는 루프 관찰자를 추가 할 수 있습니다.런 루프 관찰자를 만들려면, 당신은 CFRunLoopObserverRef 불투명 형식의 새 인스턴스를 만듭니다. 이 유형은 사용자 정의 콜백 함수와 관심이되는 활동을 추적합니다.

Similar to timers, run-loop observers can be used once or repeatedly. A one-shot observer removes itself from the run loop after it fires, while a repeating observer remains attached. You specify whether an observer runs once or repeatedly when you create it.

타이머와 유사하게, 실행 루프 관찰자가 한 번 또는 반복적으로 사용할 수 있습니다.반복 관찰자가 붙어 남아있는 동안 원샷 관찰자는 그것이 발생 후 실행 루프에서 자신을 제거합니다. 당신은 당신이 그것을 만들 때 관찰자가 한 번 또는 반복적으로 실행할지 여부를 지정합니다.

For an example of how to create a run-loop observer, see “Configuring the Run Loop.” For reference information, see CFRunLoopObserver Reference.

"실행 루프 구성"을 참조하십시오. 런 루프 관찰자를 만드는 방법에 대한 예제를 보려면 참조 정보 CFRunLoopObserver 참조를 참조하십시오.

The Run Loop Sequence of Events

이벤트의 실행 루프 시퀀스

Each time you run it, your thread’s run loop processes pending events and generates notifications for any attached observers. The order in which it does this is very specific and is as follows:

당신이 그것을 실행할 때마다, 귀하 스레드의 실행 루프 프로세스 이벤트를 보류하고 연결된 모든 관찰자에 대한 알림을 생성합니다. 그것은이 작업을 수행하는 순서는 매우 다르며 다음과 같습니다 :

  1. Notify observers that the run loop has been entered.
    런 루프가 입력되었는지 관찰자에게 알립니다.

  2. Notify observers that any ready timers are about to fire.
    모든 준비가 타이머 화재에 대한 것을 관찰자에게 알립니다.

  3. Notify observers that any input sources that are not port based are about to fire.
    포트 기반하지 않는 모든 입력 소스 화재에 대한 것을 관찰자에게 알립니다.

  4. Fire any non-port-based input sources that are ready to fire.
    발사 준비가 아닌 포트 기반 입력 소스를 화재.

  5. If a port-based input source is ready and waiting to fire, process the event immediately. Go to step 9.
    포트 기반 입력 소스가 준비 화재 기다리고있는 경우, 즉시 이벤트를 처리합니다. 9 단계로 이동합니다.

  6. Notify observers that the thread is about to sleep.
    스레드 잠을 약하는 관찰자에게 알립니다.

  7. Put the thread to sleep until one of the following events occurs:
    다음 이벤트 중 하나가 발생할 때까지 잠을 스레드를 넣어 :

    • An event arrives for a port-based input source.
      이벤트는 포트 기반의 입력 소스에 도착합니다.

    • A timer fires.
      타이머가 발생합니다.

    • The timeout value set for the run loop expires.
      운전 루프에 설정된 시간 초과 값이 만료됩니다.

    • The run loop is explicitly woken up.
      런 루프는 명시 적으로 깨어 있습니다.

  8. Notify observers that the thread just woke up.
    스레드가 방금 깨어있는 관찰자에게 알립니다.

  9. Process the pending event.
    보류중인 이벤트를 처리합니다.

    • If a user-defined timer fired, process the timer event and restart the loop. Go to step 2.
      사용자 정의 타이머가 발생하면, 타이머 이벤트를 처리하고 루프를 다시 시작합니다. 2 단계로 이동합니다.

    • If an input source fired, deliver the event.
      입력 소스가 발생하는 경우, 이벤트를 제공합니다.

    • If the run loop was explicitly woken up but has not yet timed out, restart the loop. Go to step 2.
      런 루프가 명시 적으로 깨어되었지만 아직 시간이 초과되지 않은 경우, 루프를 다시 시작합니다. 2 단계로 이동합니다.

  10. Notify observers that the run loop has exited.
    실행 루프가 종료되었음을 관찰자에게 알립니다.

Because observer notifications for timer and input sources are delivered before those events actually occur, there may be a gap between the time of the notifications and the time of the actual events. If the timing between these events is critical, you can use the sleep and awake-from-sleep notifications to help you correlate the timing between the actual events.

이러한 이벤트가 실제로 발생하기 전에 타이머 및 입력 소스에 대한 관찰자 알림이 전달되기 때문에, 알림 시간과 실제 이벤트 시간 사이에 차이가있을 수 있습니다. 이러한 이벤트 사이의 타이밍이 중요하다면, 당신은 실제 이벤트 사이의 시간 상관 관계를하는 데 도움이되는 수면과 깨어있는 -에서 - 수면 알림을 사용할 수 있습니다.

Because timers and other periodic events are delivered when you run the run loop, circumventing that loop disrupts the delivery of those events. The typical example of this behavior occurs whenever you implement a mouse-tracking routine by entering a loop and repeatedly requesting events from the application. Because your code is grabbing events directly, rather than letting the application dispatch those events normally, active timers would be unable to fire until after your mouse-tracking routine exited and returned control to the application.

당신은 루프가 해당 이벤트의 전달을 방해하는 우회, 실행 루프를 실행할 때 타이머 및 기타 정기적 인 이벤트를 전달하기 때문이다. 응용 프로그램에서 루프를 반복적으로 요청하는 이벤트를 입력하여 마우스 추적 루틴을 구현할 때마다이 문제의 전형적인 예가 발생합니다. 코드가 아닌 응용 프로그램이 일반적으로 이러한 이벤트를 전달시키는 것보다, 직접 이벤트를 잡아 때문에, 활성 타이머는 마우스 추적 루틴이 종료되고 응용 프로그램에 제어를 리턴 할 때까지 발사 할 수 없게됩니다.

A run loop can be explicitly woken up using the run loop object. Other events may also cause the run loop to be woken up. For example, adding another non-port-based input source wakes up the run loop so that the input source can be processed immediately, rather than waiting until some other event occurs.

런 루프는 명시 적으로 실행 루프 개체를 사용 깨어 수 있습니다. 다른 이벤트는 실행 루프가 깨어 될 수 있습니다. 예를 들어, 다른 비 포트 기반 입력 소스를 추가하면 입력 소스가 아닌 다른 이벤트가 발생할 때까지 기다리지 않고, 즉시 처리 될 수 있도록 실행 루프를 일어난다.

When Would You Use a Run Loop?
때 실행 루프를 사용해야합니까?

The only time you need to run a run loop explicitly is when you create secondary threads for your application. The run loop for your application’s main thread is a crucial piece of infrastructure. As a result, the app frameworks provide the code for running the main application loop and start that loop automatically. The runmethod of UIApplication in iOS (or NSApplication in OS X) starts an application’s main loop as part of the normal startup sequence. If you use the Xcode template projects to create your application, you should never have to call these routines explicitly.

당신은 명시 적으로 실행 루프를 실행하는 데 필요한 유일한 시간은 당신의 응용 프로그램에 대한 보조 스레드를 만들 때이다. 응용 프로그램의 주 스레드를 실행 루프 인프라의 중요한 부분입니다.그 결과로, 응용 프로그램 프레임 워크는 기본 응용 프로그램 루프를 실행하기위한 코드를 제공하고 자동으로 해당 루프를 시작합니다. 이오스 UIApplication의 runmethod (또는 OS X에서 NSApplication)은 정상적인 시작 시퀀스의 일부로 응용 프로그램의 메인 루프를 시작합니다. 응용 프로그램을 만들 Xcode의 템플릿 프로젝트를 사용하는 경우, 당신은 명시 적으로 이러한 루틴을 호출 할 필요가 없습니다 안됩니다.

For secondary threads, you need to decide whether a run loop is necessary, and if it is, configure and start it yourself. You do not need to start a thread’s run loop in all cases. For example, if you use a thread to perform some long-running and predetermined task, you can probably avoid starting the run loop. Run loops are intended for situations where you want more interactivity with the thread. For example, you need to start a run loop if you plan to do any of the following:

보조 스레드를 들어, 실행 루프가 필요한지 여부를 결정해야하고, 경우, 구성하고 스스로를 시작합니다. 당신은 모든 경우에 스레드의 실행 루프를 시작할 필요가 없습니다. 당신이 어떤 장기 실행 및 소정의 작업을 수행 할 스레드를 사용하는 경우, 예를 들어, 당신은 아마 실행 루프를 시작 방지 할 수 있습니다. 당신은 스레드와 더 많은 상호 작용을하려는 실행 루프 상황을위한 것입니다. 예를 들어, 당신은 다음 중 하나를 수행하려는 경우 실행 루프를 시작해야합니다 :

  • Use ports or custom input sources to communicate with other threads.
    다른 스레드와 통신 할 포트 또는 사용자 정의 입력 소스를 사용합니다.

  • Use timers on the thread.
    스레드에서 타이머를 사용합니다.

  • Use any of the performSelector… methods in a Cocoa application.
    performSelector의 ... 코코아 응용 프로그램에서 메서드를 사용합니다.

  • Keep the thread around to perform periodic tasks.
    주기적인 작업을 수행하는 주위의 스레드를 유지합니다.

If you do choose to use a run loop, the configuration and setup is straightforward. As with all threaded programming though, you should have a plan for exiting your secondary threads in appropriate situations. It is always better to end a thread cleanly by letting it exit than to force it to terminate. Information on how to configure and exit a run loop is described in “Using Run Loop Objects.”

당신이 실행 루프를 사용하도록 선택하는 경우, 구성 및 설치가 간단합니다. 그러나 모든 스레드 프로그래밍과 마찬가지로, 당신은 적절한 상황에서 보조 스레드를 종료하기위한 계획이 있어야합니다. 그것은 강제로 종료하는 것보다 그것을 종료 시켜서 완전히 스레드를 종료하는 것이 좋습니다. 구성하고 실행 루프를 종료하는 방법에 대한 정보가 설명되어 "실행 루프 개체 사용"을 참조하십시오.

Using Run Loop Objects
실행 루프 개체 사용

A run loop object provides the main interface for adding input sources, timers, and run-loop observers to your run loop and then running it. Every thread has a single run loop object associated with it. In Cocoa, this object is an instance of the NSRunLoop class. In a low-level application, it is a pointer to a CFRunLoopRefopaque type.

실행 루프 개체는 실행 루프에 입력 소스, 타이머 및 실행 루프 관찰자를 추가하고이를 실행하기위한 기본 인터페이스를 제공합니다. 모든 스레드는 그와 연관된 단일 실행 루프 개체가 있습니다. 코코아,이 객체는 NSRunLoop 클래스의 인스턴스입니다. 낮은 수준의 응용 프로그램에서는 CFRunLoopRefopaque 형식에 대한 포인터입니다.

Getting a Run Loop Object

실행 루프 개체 가져 오기

To get the run loop for the current thread, you use one of the following:
현재 스레드의 실행 루프를 얻으려면, 당신은 다음 중 하나를 사용하십시오 :

  • In a Cocoa application, use the currentRunLoop class method of NSRunLoop to retrieve an NSRunLoop object.
    코코아 응용 프로그램에서 NSRunLoop 개체를 검색 할 수 NSRunLoop의 currentRunLoop 클래스 메서드를 사용합니다.

  • Use the CFRunLoopGetCurrent function.
    CFRunLoopGetCurrent 기능을 사용합니다.

Although they are not toll-free bridged types, you can get a CFRunLoopRef opaque type from an NSRunLoop object when needed. The NSRunLoop class defines agetCFRunLoop method that returns a CFRunLoopRef type that you can pass to Core Foundation routines. Because both objects refer to the same run loop, you can intermix calls to the NSRunLoop object and CFRunLoopRef opaque type as needed.

그들은 수신자 부담 브리지 타입은 아니지만 필요할 때, 당신은 NSRunLoop 개체에서 CFRunLoopRef 불투명 한 유형을 얻을 수 있습니다.NSRunLoop 클래스를 사용하면 코어 재단 루틴에 전달할 수있는 CFRunLoopRef 형식을 반환 agetCFRunLoop 방법을 정의합니다. 두 객체가 동일한 실행 루프를 참조하므로 인터 NSRunLoop 개체와 필요에 따라 CFRunLoopRef 불투명 형식으로 호출 할 수 있습니다.

Configuring the Run Loop

실행 루프 구성

Before you run a run loop on a secondary thread, you must add at least one input source or timer to it. If a run loop does not have any sources to monitor, it exits immediately when you try to run it. For examples of how to add sources to a run loop, see “Configuring Run Loop Sources.”

당신이 보조 스레드에서 실행 루프를 실행하기 전에, 당신은 적어도 하나의 입력 소스 또는 타이머를 추가해야합니다. 당신이 그것을 실행하려고 즉시 실행 루프가 어떤 소스를 모니터링하지 않는 경우 종료합니다. 운전 루프에 소스를 추가하는 방법에 대한 예를 들어, "실행 루프 소스 구성"을 참조하십시오.

In addition to installing sources, you can also install run loop observers and use them to detect different execution stages of the run loop. To install a run loop observer, you create a CFRunLoopObserverRef opaque type and use the CFRunLoopAddObserver function to add it to your run loop. Run loop observers must be created using Core Foundation, even for Cocoa applications.

소스를 설치하는 이외에, 당신은 또한 루프 관찰자를 실행 설치하고 실행 루프의 다른 실행 단계를 감지하는 데 사용할 수 있습니다. 운전 루프 관측기를 설치하려면, 당신은 CFRunLoopObserverRef 불투명 한 유형을 작성하고 실행 루프에 추가 CFRunLoopAddObserver 함수를 사용합니다. 실행 루프 관찰자조차 코코아 응용 프로그램, 코어 파운데이션을 사용하여 작성해야합니다.

Listing 3-1 shows the main routine for a thread that attaches a run loop observer to its run loop. The purpose of the example is to show you how to create a run loop observer, so the code simply sets up a run loop observer to monitor all run loop activities. The basic handler routine (not shown) simply logs the run loop activity as it processes the timer requests.

목록 3-1은 실행 루프에 실행 된 루프 관측기를 연결 스레드에 대한 주요 루틴을 보여줍니다.예제의 목적은 어떻게 실행 루프 관측기를 만드는 방법을 보여주는 것입니다, 코드는 단순히 모든 실행 루프 활동을 모니터링하는 실행 루프 관측기를 설정하므로. 이 타이머 요청을 처리 할 때 기본 핸들러 루틴 (미도시)는 단순히 실행 루프 활동을 기록합니다.

Listing 3-1  Creating a run loop observer

- (void)threadMain
{
    // The application uses garbage collection, so no autorelease pool is needed.
    NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
 
    // Create a run loop observer and attach it to the run loop.
    CFRunLoopObserverContext  context = {0, self, NULL, NULL, NULL};
    CFRunLoopObserverRef    observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
            kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context);
 
    if (observer)
    {
        CFRunLoopRef    cfLoop = [myRunLoop getCFRunLoop];
        CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode);
    }
 
    // Create and schedule the timer.
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self
                selector:@selector(doFireTimer:) userInfo:nil repeats:YES];
 
    NSInteger    loopCount = 10;
    do
    {
        // Run the run loop 10 times to let the timer fire.
        [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
        loopCount--;
    }
    while (loopCount);
}

When configuring the run loop for a long-lived thread, it is better to add at least one input source to receive messages. Although you can enter the run loop with only a timer attached, once the timer fires, it is typically invalidated, which would then cause the run loop to exit. Attaching a repeating timer could keep the run loop running over a longer period of time, but would involve firing the timer periodically to wake your thread, which is effectively another form of polling. By contrast, an input source waits for an event to happen, keeping your thread asleep until it does.

수명이 긴 스레드의 실행 루프를 구성 할 때, 메시지를 수신하는 적어도 하나의 입력 소스를 추가하는 것이 좋습니다. 당신은 타이머 번 타이머 화재, 부착 된 실행 루프를 입력 할 수 있지만, 일반적으로 다음 종료 실행 루프를 발생할 것이라고하는 무효화됩니다.반복 타이머를 부착하는 것은 시간의 긴 기간 동안 실행되는 실행 루프를 유지할 수 있지만, 효율적으로 폴링 또 다른 형태의 당신의 스레드를 깨워 주기적으로 타이머를 발사 포함됩니다. 대조적으로, 입력 소스는 않게 될 때까지 잠의 스레드를 유지, 발생하는 이벤트를 기다립니다.

Starting the Run Loop

실행 루프 시작

Starting the run loop is necessary only for the secondary threads in your application. A run loop must have at least one input source or timer to monitor. If one is not attached, the run loop exits immediately.

런 루프를 시작하는 경우에만 응용 프로그램에서 보조 스레드가 필요합니다.런 루프는 적어도 하나의 입력 소스 또는 모니터링 할 타이머를 가지고 있어야합니다. 하나가 연결되어 있지 않은 경우, 실행 루프가 종료 즉시.

There are several ways to start the run loop, including the following:
다음과 같은 실행 루프를 시작하는 몇 가지 방법이 있습니다 :

  • Unconditionally
    무조건

  • With a set time limit
    설정된 시간 한도

  • In a particular mode
    특정 모드에서

Entering your run loop unconditionally is the simplest option, but it is also the least desirable. Running your run loop unconditionally puts the thread into a permanent loop, which gives you very little control over the run loop itself. You can add and remove input sources and timers, but the only way to stop the run loop is to kill it. There is also no way to run the run loop in a custom mode.

러닝 루프를 입력하면 무조건 간단한 방법이지만, 그것은 또한 가장 바람직하다. 러닝 루프를 실행하면 무조건 당신에게 실행 루프 자체에 거의 제어 할 수있는 영구 루프에 실을 넣습니다. 당신은 추가 및 제거 입력 소스 및 타이머,하지만 실행 루프를 막을 수있는 유일한 방법은 그것을 죽일 것입니다 수 있습니다.사용자 정의 모드에서 실행 루프를 실행하는 방법은 없습니다.

Instead of running a run loop unconditionally, it is better to run the run loop with a timeout value. When you use a timeout value, the run loop runs until an event arrives or the allotted time expires. If an event arrives, that event is dispatched to a handler for processing and then the run loop exits. Your code can then restart the run loop to handle the next event. If the allotted time expires instead, you can simply restart the run loop or use the time to do any needed housekeeping.

대신 무조건 실행 루프를 실행, 그것은 시간 초과 값과 실행 루프를 실행하는 것이 좋습니다. 당신이 제한 시간 값을 사용하면, 이벤트가 도착할 때까지 실행 루프를 실행하거나 할당 된 시간이 만료됩니다.이벤트가 도착하면 그 이벤트 처리를위한 핸들러하고 실행 루프가 종료로 전달됩니다. 귀하의 코드는 다음 이벤트를 처리하는 실행 루프를 다시 시작할 수 있습니다.할당 된 시간 대신 만료되면, 당신은 단순히 실행 루프를 다시 시작하거나 필요한 모든 하우스 키핑을 할 수있는 시간을 사용할 수 있습니다.

In addition to a timeout value, you can also run your run loop using a specific mode. Modes and timeout values are not mutually exclusive and can both be used when starting a run loop. Modes limit the types of sources that deliver events to the run loop and are described in more detail in “Run Loop Modes.”

시간 제한 값 이외에, 당신은 또한 특정 모드를 사용하여 실행 된 루프를 실행할 수 있습니다. 모드와 타임 아웃 값은 상호 배타적이지하고 실행 루프를 시작할 때 모두 사용할 수 있습니다. 모드는 런 루프에 이벤트를 전달하고에 자세히 설명되어 소스의 유형을 제한하는 "실행 루프 모드."

Listing 3-2 shows a skeleton version of a thread’s main entry routine. The key portion of this example shows the basic structure of a run loop. In essence, you add your input sources and timers to the run loop and then repeatedly call one of the routines to start the run loop. Each time the run loop routine returns, you check to see if any conditions have arisen that might warrant exiting the thread. The example uses the Core Foundation run loop routines so that it can check the return result and determine why the run loop exited. You could also use the methods of the NSRunLoop class to run the run loop in a similar manner if you are using Cocoa and do not need to check the return value. (For an example of a run loop that calls methods of the NSRunLoop class, see Listing 3-14.)

목록 3-2 스레드의 주 진입 루틴의 뼈대 버전을 보여줍니다. 이 예제의 핵심 부분은 실행 루프의 기본 구조를 보여줍니다. 본질적으로, 당신은 실행 루프에 입력 소스 및 타이머를 추가 한 다음 반복 실행 루프를 시작하는 루틴 중 하나를 호출합니다.런 루프 루틴을 반환 할 때마다, 당신은 어떤 조건이 스레드를 종료 보증 수 있다는 생겨이 있는지 확인하십시오. 그것은 반환 결과를 확인하고 실행 루프가 종료 이유를 확인할 수 있도록 예제는 코어 파운데이션 실행 루프 루틴을 사용합니다. 당신은 또한 코코아를 사용하고 반환 값을 확인할 필요가없는 경우 비슷한 방식으로 실행 루프를 실행 NSRunLoop 클래스의 메서드를 사용할 수 있습니다. (NSRunLoop 클래스의 메서드를 호출하는 실행 루프의 예를 들어, Listing 3-14을 참조하십시오.)

Listing 3-2  Running a run loop

- (void)skeletonThreadMain
{
    // Set up an autorelease pool here if not using garbage collection.
    BOOL done = NO;
 
    // Add your sources or timers to the run loop and do any other setup.
 
    do
    {
        // Start the run loop but return after each source is handled.
        SInt32    result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES);
 
        // If a source explicitly stopped the run loop, or if there are no
        // sources or timers, go ahead and exit.
        if ((result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished))
            done = YES;
 
        // Check for any other exit conditions here and set the
        // done variable as needed.
    }
    while (!done);
 
    // Clean up code here. Be sure to release any allocated autorelease pools.
}

It is possible to run a run loop recursively. In other words, you can call CFRunLoopRunCFRunLoopRunInMode, or any of the NSRunLoop methods for starting the run loop from within the handler routine of an input source or timer. When doing so, you can use any mode you want to run the nested run loop, including the mode in use by the outer run loop.

그것은 재귀 적으로 실행 루프를 실행할 수 있습니다. 즉, 당신은 CFRunLoopRun, CFRunLoopRunInMode, 또는 입력 소스 또는 타이머 핸들러 루틴 내에서 실행 루프를 시작하기위한 NSRunLoop 방법 중 하나를 호출 할 수 있습니다. 이렇게하면, 당신은 외부 실행 루프에서 사용하는 모드를 포함하는 중첩 된 실행 루프를 실행하고자하는 모드를 사용할 수 있습니다.

Exiting the Run Loop

실행 루프를 종료

There are two ways to make a run loop exit before it has processed an event:
이 이벤트를 처리하기 전에 실행 루프 출구를 만들기 위해 두 가지 방법이 있습니다 :

  • Configure the run loop to run with a timeout value.
    시간 초과 값으로 실행하는 실행 루프를 구성합니다.

  • Tell the run loop to stop.
    중지 실행 루프를 말한다.

Using a timeout value is certainly preferred, if you can manage it. Specifying a timeout value lets the run loop finish all of its normal processing, including delivering notifications to run loop observers, before exiting.

당신이 그것을 관리 할 수있는 경우 시간 초과 값을 사용하면 확실히 좋습니다.시간 초과 값을 지정하면 실행 루프가 종료하기 전에 루프 관찰자를 실행하는 알림을 제공하는 등의 정상적인 처리를 모두 완료 할 수 있습니다.

Stopping the run loop explicitly with the CFRunLoopStop function produces a result similar to a timeout. The run loop sends out any remaining run-loop notifications and then exits. The difference is that you can use this technique on run loops you started unconditionally.

CFRunLoopStop 기능을 명시 적으로 실행 루프를 중지하면 시간 초과로 유사한 결과를 생성합니다.런 루프는 남아있는 실행 루프 알림 및 다음 종료를 보냅니다.차이점은 당신이 무조건 시작 실행 루프에서이 기술을 사용할 수 있다는 것입니다.

Although removing a run loop’s input sources and timers may also cause the run loop to exit, this is not a reliable way to stop a run loop. Some system routines add input sources to a run loop to handle needed events. Because your code might not be aware of these input sources, it would be unable to remove them, which would prevent the run loop from exiting.

운전 루프의 입력 소스와 타이머를 제거하는 것이 아니라 실행 루프가 종료 될 수 있지만,이 런 루프를 막을 수있는 확실한 방법이 아닙니다. 일부 시스템 루틴은 필요한 이벤트를 처리 할 수있는 실행 루프에 입력 소스를 추가합니다. 코드가 이러한 입력 소스를 인식하지 못할 수 있으므로, 그것은 종료에서 실행 루프를 방지 할 그들을 제거 할 수없는 것입니다.

Thread Safety and Run Loop Objects

스레드 안전 및 실행 루프 개체

Thread safety varies depending on which API you are using to manipulate your run loop. The functions in Core Foundation are generally thread-safe and can be called from any thread. If you are performing operations that alter the configuration of the run loop, however, it is still good practice to do so from the thread that owns the run loop whenever possible.

스레드 안전은 당신의 런 루프를 조작하는 데 사용되는 API에 따라 달라집니다. 코어 파운데이션의 기능은 일반적으로 스레드 안전하며 모든 스레드에서 호출 할 수 있습니다. 당신이 실행 된 루프의 구성을 변경 작업을 수행하는 경우, 그러나, 그것은 여전히 가능 런 루프마다를 소유 한 스레드에서 그렇게하는 것이 좋습니다.

The Cocoa NSRunLoop class is not as inherently thread safe as its Core Foundation counterpart. If you are using the NSRunLoop class to modify your run loop, you should do so only from the same thread that owns that run loop. Adding an input source or timer to a run loop belonging to a different thread could cause your code to crash or behave in an unexpected way.

코코아 NSRunLoop 클래스는 핵심 재단 대응만큼 본질적으로 스레드로부터 안전하지 않습니다. 당신이 실행 루프를 수정하는 NSRunLoop 클래스를 사용하는 경우, 당신은 실행되는 루프를 소유하고 동일한 스레드에서 그렇게해야한다.다른 스레드에 속한 런 루프에 입력 소스 또는 타이머를 추가하면 예상치 못한 방식으로 충돌하거나 작동하도록 코드를 발생할 수 있습니다.

Configuring Run Loop Sources
런 루프 소스 구성

The following sections show examples of how to set up different types of input sources in both Cocoa and Core Foundation.

다음 섹션에서는 코코아 및 핵심 기초 모두 입력 소스의 다른 유형을 설정하는 방법의 예를 보여줍니다.

Defining a Custom Input Source

사용자 정의 입력 소스를 정의

Creating a custom input source involves defining the following:
사용자 정의 입력 소스를 작성하면 다음과 같은 정의를 포함한다 :

  • The information you want your input source to process.
    당신이 입력 소스가 처리 할 정보를 제공합니다.

  • A scheduler routine to let interested clients know how to contact your input source.
    스케줄러 루틴 관심이 클라이언트가 입력 소스를 접촉하는 방법을 알려 수 있습니다.

  • A handler routine to perform requests sent by any clients.
    모든 클라이언트에서 보낸 요청을 수행하는 처리기 루틴.

  • A cancellation routine to invalidate your input source.
    입력 소스를 무효화 취소 루틴.

Because you create a custom input source to process custom information, the actual configuration is designed to be flexible. The scheduler, handler, and cancellation routines are the key routines you almost always need for your custom input source. Most of the rest of the input source behavior, however, happens outside of those handler routines. For example, it is up to you to define the mechanism for passing data to your input source and for communicating the presence of your input source to other threads.

당신이 사용자 정의 정보를 처리하는 사용자 정의 입력 소스를 만들기 때문에, 실제 구성이 유연하도록 설계되었습니다.스케줄러, 처리기 및 취소 루틴은 당신은 거의 항상 사용자 정의 입력 소스에 필요한 핵심 루틴입니다.입력 소스 행동의 나머지의 대부분은, 그러나, 그 핸들러 루틴의 외부에서 발생합니다. 예를 들어, 입력 소스에 데이터를 전달하는 다른 스레드에 입력 소스의 존재를 통신하기위한 메커니즘을 정의하기 위해 당신에게 달려있다.

Figure 3-2 shows a sample configuration of a custom input source. In this example, the application’s main thread maintains references to the input source, the custom command buffer for that input source, and the run loop on which the input source is installed. When the main thread has a task it wants to hand off to the worker thread, it posts a command to the command buffer along with any information needed by the worker thread to start the task. (Because both the main thread and the input source of the worker thread have access to the command buffer, that access must be synchronized.) Once the command is posted, the main thread signals the input source and wakes up the worker thread’s run loop. Upon receiving the wake up command, the run loop calls the handler for the input source, which processes the commands found in the command buffer.

그림 3-2은 사용자 정의 입력 소스의 샘플 구성을 보여줍니다. 이 예제에서는 응용 프로그램의 주 스레드는 입력 소스가 입력 소스에 대한 사용자 지정 명령 버퍼, 입력 소스가 설치되어있는 실행 루프에 대한 참조를 유지합니다.작업을 시작하기 위해 작업자 스레드에 의해 필요한 정보와 함께 주 스레드는 작업자 스레드에 넘겨 원하는 작업을, 그것이 게시물 명령 버퍼에 명령을 실행합니다. 명령이 게시되면 (메인 스레드와 작업자 스레드의 입력 소스를 모두 명령어 버퍼에 액세스 할 수 있기 때문에, 그 액세스를 동기화해야합니다.), 메인 쓰레드는 입력 소스 신호와 작업자 스레드의 실행 루프 일어난다. 명령의 Wake Up을 수신하면, 실행 루프는 명령어 버퍼에있는 명령을 처리하는 입력 소스에 대한 핸들러를 호출합니다.

Figure 3-2  Operating a custom input source
Operating a custom input source

The following sections explain the implementation of the custom input source from the preceding figure and show the key code you would need to implement.

다음 절에는 위의 그림에서 사용자 정의 입력 소스의 구현을 설명하고 구현해야 할 키 코드를 보여줍니다.

Defining the Input Source

입력 소스를 정의

Defining a custom input source requires the use of Core Foundation routines to configure your run loop source and attach it to a run loop. Although the basic handlers are C-based functions, that does not preclude you from writing wrappers for those functions and using Objective-C or C++ to implement the body of your code.
사용자 정의 입력 소스를 정의하면 실행 루프 소스를 구성하고 실행 루프에 연결하는 핵심 재단 루틴의 사용을 필요로합니다.기본 핸들러는 C 기반 기능이지만, 그 해당 함수에 대한 래퍼를 작성하고 사용하는 것을 배제하지 않는다 오브젝티브-C 또는 C + + 코드의 몸을 구현합니다.

The input source introduced in Figure 3-2 uses an Objective-C object to manage a command buffer and coordinate with the run loop. Listing 3-3 shows the definition of this object. The RunLoopSource object manages a command buffer and uses that buffer to receive messages from other threads. This listing also shows the definition of the RunLoopContext object, which is really just a container object used to pass a RunLoopSource object and a run loop reference to the application’s main thread.

그림 3-2에 소개 된 입력 소스는 명령 버퍼를 관리하고 실행 루프를 조정하는 오브젝티브-C 객체를 사용합니다. 목록 3-3은이 객체의 정의를 보여줍니다.RunLoopSource 개체는 명령어 버퍼를 관리하고 다른 스레드에서 메시지를 수신하는 버퍼를 사용합니다. 이 목록은 정말 RunLoopSource 개체와 응용 프로그램의 주 스레드에 실행 된 루프 참조를 전달하는 데 사용되는 단지 컨테이너 개체입니다 RunLoopContext 개체의 정의를 보여줍니다.

Listing 3-3  The custom input source object definition

@interface RunLoopSource : NSObject
{
    CFRunLoopSourceRef runLoopSource;
    NSMutableArray* commands;
}
 
- (id)init;
- (void)addToCurrentRunLoop;
- (void)invalidate;
 
// Handler method
- (void)sourceFired;
 
// Client interface for registering commands to process
- (void)addCommand:(NSInteger)command withData:(id)data;
- (void)fireAllCommandsOnRunLoop:(CFRunLoopRef)runloop;
 
@end
 
// These are the CFRunLoopSourceRef callback functions.
void RunLoopSourceScheduleRoutine (void *info, CFRunLoopRef rl, CFStringRef mode);
void RunLoopSourcePerformRoutine (void *info);
void RunLoopSourceCancelRoutine (void *info, CFRunLoopRef rl, CFStringRef mode);
 
// RunLoopContext is a container object used during registration of the input source.
@interface RunLoopContext : NSObject
{
    CFRunLoopRef        runLoop;
    RunLoopSource*        source;
}
@property (readonly) CFRunLoopRef runLoop;
@property (readonly) RunLoopSource* source;
 
- (id)initWithSource:(RunLoopSource*)src andLoop:(CFRunLoopRef)loop;
@end

Although the Objective-C code manages the custom data of the input source, attaching the input source to a run loop requires C-based callback functions. The first of these functions is called when you actually attach the run loop source to your run loop, and is shown in Listing 3-4. Because this input source has only one client (the main thread), it uses the scheduler function to send a message to register itself with the application delegate on that thread. When the delegate wants to communicate with the input source, it uses the information in RunLoopContext object to do so.

목표-C 코드는 입력 소스의 사용자 지정 데이터를 관리하지만, 실행 루프에 입력 소스를 연결하면 C-기반의 콜백 함수가 필요합니다. 이 함수의 첫 번째는 사용자가 실제로 실행 루프로 실행 루프 소스를 연결할 때 호출되며, 3-4 목록에 표시됩니다. 이 입력 소스는 하나의 클라이언트 (메인 스레드)를 가지고 있기 때문에, 그 스레드에서 응용 프로그램 대리자 자체를 등록하는 메시지를 보낼 스케줄러 함수를 사용합니다. 대리자가 입력 소스와 통신하고자 할 때, 그것은 그렇게 할 RunLoopContext 객체에 정보를 사용합니다.

Listing 3-4  Scheduling a run loop source

void RunLoopSourceScheduleRoutine (void *info, CFRunLoopRef rl, CFStringRef mode)
{
    RunLoopSource* obj = (RunLoopSource*)info;
    AppDelegate*   del = [AppDelegate sharedAppDelegate];
    RunLoopContext* theContext = [[RunLoopContext alloc] initWithSource:obj andLoop:rl];
 
    [del performSelectorOnMainThread:@selector(registerSource:)
                                withObject:theContext waitUntilDone:NO];
}

One of the most important callback routines is the one used to process custom data when your input source is signaled. Listing 3-5 shows the perform callback routine associated with the RunLoopSource object. This function simply forwards the request to do the work to the sourceFired method, which then processes any commands present in the command buffer.

가장 중요한 콜백 루틴 중 하나는 입력 소스가 신호를하면 사용자 지정 데이터를 처리하는 데 사용되는 하나입니다. 목록 3-5은 RunLoopSource 객체와 연관된 콜백 루틴을 수행 보여줍니다. 이 함수는 단순히 요청을 전달 다음 명령어 버퍼에 존재하는 모든 명령을 처리 sourceFired 방법으로 작업을 수행합니다.

Listing 3-5  Performing work in the input source

void RunLoopSourcePerformRoutine (void *info)
{
    RunLoopSource*  obj = (RunLoopSource*)info;
    [obj sourceFired];
}

If you ever remove your input source from its run loop using the CFRunLoopSourceInvalidate function, the system calls your input source’s cancellation routine. You can use this routine to notify clients that your input source is no longer valid and that they should remove any references to it. Listing 3-6 shows the cancellation callback routine registered with the RunLoopSource object. This function sends another RunLoopContext object to the application delegate, but this time asks the delegate to remove references to the run loop source.

당신은 CFRunLoopSourceInvalidate 기능을 사용하여 실행 루프에서 입력 소스를 제거하면 시스템은 입력 소스의 취소 루틴을 호출합니다. 당신은 입력 소스가 더 이상 유효하지 않으며 그들이에 대한 참조를 제거해야한다는 것을 클라이언트에게 알리도록하려면이 루틴을 사용할 수 있습니다. 목록 3-6 RunLoopSource 개체에 등록 취소 콜백 루틴을 보여줍니다. 이 기능은 응용 프로그램 대리자에 다른 RunLoopContext 객체를 보내지 만 이번에는 실행 루프 소스에 대한 참조를 제거하는 대리자를 요청합니다.

Listing 3-6  Invalidating an input source

void RunLoopSourceCancelRoutine (void *info, CFRunLoopRef rl, CFStringRef mode)
{
    RunLoopSource* obj = (RunLoopSource*)info;
    AppDelegate* del = [AppDelegate sharedAppDelegate];
    RunLoopContext* theContext = [[RunLoopContext alloc] initWithSource:obj andLoop:rl];
 
    [del performSelectorOnMainThread:@selector(removeSource:)
                                withObject:theContext waitUntilDone:YES];
}

Installing the Input Source on the Run Loop

운전 루프에 입력 소스를 설치

Listing 3-7 shows the init and addToCurrentRunLoop methods of the RunLoopSource class. The init method creates the CFRunLoopSourceRef opaque type that must actually be attached to the run loop. It passes the RunLoopSource object itself as the contextual information so that the callback routines have a pointer to the object. Installation of the input source does not occur until the worker thread invokes the addToCurrentRunLoop method, at which point theRunLoopSourceScheduleRoutine callback function is called. Once the input source is added to the run loop, the thread can run its run loop to wait on it.

목록 3-7 RunLoopSource 클래스의 초기화 및 addToCurrentRunLoop 방법을 보여줍니다.init 메소드는 실제로 실행 루프에 연결해야합니다 CFRunLoopSourceRef 불투명 한 형식을 만듭니다.콜백 루틴 개체에 대한 포인터를 가지고 그래서 컨텍스트 정보로 RunLoopSource 객체 자체를 전달합니다.작업자 스레드 포인트 theRunLoopSourceScheduleRoutine 콜백 함수가 호출되는 addToCurrentRunLoop 메서드를 호출 할 때까지 입력 소스의 설치는 발생하지 않습니다. 입력 소스가 실행 루프에 추가되면, 쓰레드는 기다림의 실행 루프를 실행할 수 있습니다.

Listing 3-7  Installing the run loop source

- (id)init
{
    CFRunLoopSourceContext    context = {0, self, NULL, NULL, NULL, NULL, NULL,
                                        &RunLoopSourceScheduleRoutine,
                                        RunLoopSourceCancelRoutine,
                                        RunLoopSourcePerformRoutine};
 
    runLoopSource = CFRunLoopSourceCreate(NULL, 0, &context);
    commands = [[NSMutableArray alloc] init];
 
    return self;
}
 
- (void)addToCurrentRunLoop
{
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
}

Coordinating with Clients of the Input Source

입력 소스의 클라이언트와 협조

For your input source to be useful, you need to manipulate it and signal it from another thread. The whole point of an input source is to put its associated thread to sleep until there is something to do. That fact necessitates having other threads in your application know about the input source and have a way to communicate with it.

입력 소스가 유용하려면, 당신은 그것을 조작하고 다른 스레드에서 신호를해야합니다.입력 소스의 요점은 할 수있는 뭔가가있을 때까지 잠을 관련 스레드를 넣어하는 것입니다. 그 사실이 응용 프로그램의 다른 스레드가 입력 소스에 대해 알고와 통신 할 수있는 방법이 필요 필요로한다.

One way to notify clients about your input source is to send out registration requests when your input source is first installed on its run loop. You can register your input source with as many clients as you want, or you can simply register it with some central agency that then vends your input source to interested clients. Listing 3-8 shows the registration method defined by the application delegate and invoked when the RunLoopSource object’s scheduler function is called. This method receives the RunLoopContext object provided by the RunLoopSource object and adds it to its list of sources. This listing also shows the routine used to unregister the input source when it is removed from its run loop.

입력 소스에 대해 클라이언트에 통지하는 한 가지 방법은 입력 소스가 먼저 실행 루프에 설치되어있는 경우 등록 요청을 보내는 것입니다. 당신이 원하는대로 당신은 많은 클라이언트와 입력 소스를 등록 할 수 있습니다, ​​또는 당신은 단순히 그 관심이 클라이언트에 입력 소스를 vends 일부 중앙 기관에 등록 할 수 있습니다. 목록 3-8 응용 프로그램 대리자에 의해 정의 및 RunLoopSource 객체의 스케줄러 함수가 호출 될 때 호출되는 등록 방법을 보여줍니다. 이 방법은 RunLoopSource 개체에서 제공 RunLoopContext 객체를 수신하고 소스 목록에 추가합니다. 이 목록은 또한 그것의 실행 루프에서 제거 될 때 입력 소스 등록을 취소하는 데 사용되는 루틴을 보여줍니다.

Listing 3-8  Registering and removing an input source with the application delegate

- (void)registerSource:(RunLoopContext*)sourceInfo;
{
    [sourcesToPing addObject:sourceInfo];
}
 
- (void)removeSource:(RunLoopContext*)sourceInfo
{
    id    objToRemove = nil;
 
    for (RunLoopContext* context in sourcesToPing)
    {
        if ([context isEqual:sourceInfo])
        {
            objToRemove = context;
            break;
        }
    }
 
    if (objToRemove)
        [sourcesToPing removeObject:objToRemove];
}

Signaling the Input Source

입력 소스 신호

After it hands off its data to the input source, a client must signal the source and wake up its run loop. Signaling the source lets the run loop know that the source is ready to be processed. And because the thread might be asleep when the signal occurs, you should always wake up the run loop explicitly. Failing to do so might result in a delay in processing the input source.

이 입력 소스로 데이터를 넘겨 한 후, 클라이언트는 소스 신호 및 실행 루프를 깨워해야합니다.소스 신호는 실행 루프 소스를 처리 할 준비가되어 있음을 알 수 있습니다.신호가 발생하면 스레드가 잠들 수 있기 때문에, 당신은 항상 명시 적으로 실행 루프를 깨워해야합니다. 이렇게하지 않으면 입력 소스를 처리 지연 될 수 있습니다.

Listing 3-9 shows the fireCommandsOnRunLoop method of the RunLoopSource object. Clients invoke this method when they are ready for the source to process the commands they added to the buffer.

목록 3-9 RunLoopSource 개체의 fireCommandsOnRunLoop 방법을 보여줍니다. 그들이 버퍼에 추가 된 명령을 처리하는 소스에 대한 준비가되면 클라이언트는이 메서드를 호출합니다.

Listing 3-9  Waking up the run loop

- (void)fireCommandsOnRunLoop:(CFRunLoopRef)runloop
{
    CFRunLoopSourceSignal(runLoopSource);
    CFRunLoopWakeUp(runloop);
}

Configuring Timer Sources

타이머 소스 구성

To create a timer source, all you have to do is create a timer object and schedule it on your run loop. In Cocoa, you use the NSTimer class to create new timer objects, and in Core Foundation you use the CFRunLoopTimerRef opaque type. Internally, the NSTimer class is simply an extension of Core Foundation that provides some convenience features, like the ability to create and schedule a timer using the same method.

타이머 소스를 만들려면, 당신이해야 할 모든 타이머 개체를 생성하고 실행 루프를 예약합니다. 코코아, 당신은 새로운 타이머 개체를 만들 수 NSTimer 클래스를 사용하고 코어 재단에서 당신은 CFRunLoopTimerRef 불투명 한 형식을 사용합니다. 내부적으로 NSTimer 클래스는 단순히 동일한 방법을 사용하여 타이머를 생성하고 예약 할 수있는 능력과 같은 몇 가지 편의 기능을 제공하는 코어 파운데이션의 확장입니다.

In Cocoa, you can create and schedule a timer all at once using either of these class methods:
코코아에서는 이러한 클래스 메소드 중 하나를 사용하여 한 번에 타이머를 생성하고 예약 할 수 있습니다 :

These methods create the timer and add it to the current thread’s run loop in the default mode (NSDefaultRunLoopMode). You can also schedule a timer manually if you want by creating your NSTimer object and then adding it to the run loop using the addTimer:forMode: method of NSRunLoop. Both techniques do basically the same thing but give you different levels of control over the timer’s configuration. For example, if you create the timer and add it to the run loop manually, you can do so using a mode other than the default mode. Listing 3-10 shows how to create timers using both techniques. The first timer has an initial delay of 1 second but then fires regularly every 0.1 seconds after that. The second timer begins firing after an initial 0.2 second delay and then fires every 0.2 seconds after that.

이러한 메서드는 타이머를 생성하고 기본 모드 (NSDefaultRunLoopMode)에서 현재 스레드의 실행 루프를 추가합니다. 당신은 당신이 원하는 경우 또한 NSTimer 객체를 생성하여 수동으로 타이머를 예약하고 addTimer를 사용하여 실행 된 루프에 추가 할 수 있습니다 forMode : NSRunLoop의 방법. 두 기술은 기본적으로 같은 일을하지만, 당신이 타이머의 구성을 통해 여러 가지 수준의 제어를 제공합니다. 타이머를 생성하고 수동으로 실행 루프를 추가하는 경우 예를 들어, 기본 모드 이외의 모드를 사용하여 수행 할 수 있습니다. 목록 3-10는 두 기술을 사용하여 타이머를 만드는 방법을 보여줍니다.첫 번째 타이머는 1 초 초기 지연을 가지고하지만 그 후 정기적으로 모든 0.1 초 발생합니다.두 번째 타이머는 초기 0.2 초 지연 후 발사 시작하고 그 후 매 0.2 초 발생합니다.

Listing 3-10  Creating and scheduling timers using NSTimer

NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
 
// Create and schedule the first timer.
NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate
                        interval:0.1
                        target:self
                        selector:@selector(myDoFireTimer1:)
                        userInfo:nil
                        repeats:YES];
[myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode];
 
// Create and schedule the second timer.
[NSTimer scheduledTimerWithTimeInterval:0.2
                        target:self
                        selector:@selector(myDoFireTimer2:)
                        userInfo:nil
                        repeats:YES];

Listing 3-11 shows the code needed to configure a timer using Core Foundation functions. Although this example does not pass any user-defined information in the context structure, you could use this structure to pass around any custom data you needed for your timer. For more information about the contents of this structure, see its description in CFRunLoopTimer Reference.

목록 3-11는 코드가 코어 파운데이션 함수를 사용하여 타이머를 구성하는 데 필요한 보여줍니다. 이 예제 컨텍스트 구조에서 사용자 정의 된 정보를 전달하지 않지만, 당신은 당신의 타이머에 필요한 모든 사용자 지정 데이터 주위에 전달하기 위해이 구조를 사용할 수 있습니다. 이 구조체의 내용에 대한 자세한 내용은 CFRunLoopTimer 참조 설명서에서 해당 설명을 참조하십시오.

Listing 3-11  Creating and scheduling a timer using Core Foundation

CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFRunLoopTimerContext context = {0, NULL, NULL, NULL, NULL};
CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, 0.1, 0.3, 0, 0,
                                        &myCFTimerCallback, &context);
 
CFRunLoopAddTimer(runLoop, timer, kCFRunLoopCommonModes);

Configuring a Port-Based Input Source

포트 기반 입력 소스 구성

Both Cocoa and Core Foundation provide port-based objects for communicating between threads or between processes. The following sections show you how to set up port communication using several different types of ports.

코코아 및 핵심 기초는 모두 스레드 간 또는 프로세스 간 통신을위한 포트 기반 개체를 제공합니다.다음 섹션에서는 포트의 여러 가지 유형을 사용하여 포트 통신을 설정하는 방법을 보여줍니다.

Configuring an NSMachPort Object

NSMachPort 개체 구성

To establish a local connection with an NSMachPort object, you create the port object and add it to your primary thread's run loop. When launching your secondary thread, you pass the same object to your thread's entry-point function. The secondary thread can use the same object to send messages back to your primary thread.

NSMachPort 객체에 로컬 연결을 설정하려면, 포트 개체를 만들고 기본 스레드의 실행 루프에 추가합니다. 보조 스레드를 시작할 때, 당신은 당신의 스레드의 엔트리 포인트 함수에 동일한 개체를 전달합니다.보조 스레드는 주 스레드에 메시지를 다시 보낼 동일한 개체를 사용할 수 있습니다.

Implementing the Main Thread Code

메인 스레드 코드를 구현

Listing 3-12 shows the primary thread code for launching a secondary worker thread. Because the Cocoa framework performs many of the intervening steps for configuring the port and run loop, the launchThread method is noticeably shorter than its Core Foundation equivalent (Listing 3-17); however, the behavior of the two is nearly identical. One difference is that instead of sending the name of the local port to the worker thread, this method sends the NSPort object directly.

목록 3-12 보조 작업자 스레드를 시작하기위한 기본 스레드 코드를 보여줍니다.코코아 프레임 워크 포트 및 실행 루프를 구성하기위한 중간 단계의 많은 수행하기 때문에, launchThread 방법의 핵심 재단에 해당한다 (Listing 3-17)보다 눈에 띄게 짧아하지만, 두 가지의 동작은 거의 동일합니다. 한 가지 차이점은 대신 작업자 스레드 로컬 포트​​의 이름을 보내는이 방법은 직접 NSPort 객체를 전송하는 것입니다.

Listing 3-12  Main thread launch method

- (void)launchThread
{
    NSPort* myPort = [NSMachPort port];
    if (myPort)
    {
        // This class handles incoming port messages.
        [myPort setDelegate:self];
 
        // Install the port as an input source on the current run loop.
        [[NSRunLoop currentRunLoop] addPort:myPort forMode:NSDefaultRunLoopMode];
 
        // Detach the thread. Let the worker release the port.
        [NSThread detachNewThreadSelector:@selector(LaunchThreadWithPort:)
               toTarget:[MyWorkerClass class] withObject:myPort];
    }
}

In order to set up a two-way communications channel between your threads, you might want to have the worker thread send its own local port to your main thread in a check-in message. Receiving the check-in message lets your main thread know that all went well in launching the second thread and also gives you a way to send further messages to that thread.

귀하의 스레드 간의 양방향 통신 채널을 설정하기 위해서는, 당신은 작업자 스레드 체크인 메시지에서 주 스레드에 자신의 로컬 포트​​를 전송하도록 할 수 있습니다. 받은 체크에 메시지를 메인 스레드가 모두 두 번째 스레드를 실행에 잘 갔다 것을 알 수 있습니다 또한 당신에게 해당 스레드에 추가 메시지를 보낼 수있는 방법을 제공합니다.에게

Listing 3-13 shows the handlePortMessage: method for the primary thread. This method is called when data arrives on the thread's own local port. When a check-in message arrives, the method retrieves the port for the secondary thread directly from the port message and saves it for later use.

기본 스레드 방법 : 목록 3-13 handlePortMessage를 보여줍니다. 데이터를 스레드의 고유 한 로컬 포트에 도착하면이 메서드가 호출됩니다. 때 체크에 메시지가 도착, 방법은 직접 포트 메시지에서 보조 스레드에 대한 포트를 검색하고 나중에 사용하기 위해 저장합니다.

Listing 3-13  Handling Mach port messages

#define kCheckinMessage 100
 
// Handle responses from the worker thread.
- (void)handlePortMessage:(NSPortMessage *)portMessage
{
    unsigned int message = [portMessage msgid];
    NSPort* distantPort = nil;
 
    if (message == kCheckinMessage)
    {
        // Get the worker thread’s communications port.
        distantPort = [portMessage sendPort];
 
        // Retain and save the worker port for later use.
        [self storeDistantPort:distantPort];
    }
    else
    {
        // Handle other messages.
    }
}
Implementing the Secondary Thread Code

보조 스레드 코드를 구현

For the secondary worker thread, you must configure the thread and use the specified port to communicate information back to the primary thread.

보조 작업자 스레드를 들어, 스레드를 구성하고 기본 스레드로 정보를 전달하기 위해 지정된 포트를 사용해야합니다.

Listing 3-14 shows the code for setting up the worker thread. After creating an autorelease pool for the thread, the method creates a worker object to drive the thread execution. The worker object’s sendCheckinMessage: method (shown in Listing 3-15) creates a local port for the worker thread and sends a check-in message back to the main thread.

목록 3-14 작업자 스레드를 설정하는 코드를 보여줍니다.스레드 autorelease를 풀을 만든 후,이 메소드는 스레드 실행을 유도하는 작업자 개체를 만듭니다.작업자 개체의 sendCheckinMessage : 메소드 (목록 3-15) 작업자 스레드 로컬 포트​​를 생성하고 전송 체크인 다시 메인 스레드에 메시지가 표시됩니다.

Listing 3-14  Launching the worker thread using Mach ports

+(void)LaunchThreadWithPort:(id)inData
{
    NSAutoreleasePool*  pool = [[NSAutoreleasePool alloc] init];
 
    // Set up the connection between this thread and the main thread.
    NSPort* distantPort = (NSPort*)inData;
 
    MyWorkerClass*  workerObj = [[self alloc] init];
    [workerObj sendCheckinMessage:distantPort];
    [distantPort release];
 
    // Let the run loop process things.
    do
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                            beforeDate:[NSDate distantFuture]];
    }
    while (![workerObj shouldExit]);
 
    [workerObj release];
    [pool release];
}

When using NSMachPort, local and remote threads can use the same port object for one-way communication between the threads. In other words, the local port object created by one thread becomes the remote port object for the other thread.

NSMachPort를 사용할 때, 로컬 및 원격 스레드는 스레드 간의 단방향 통신을 위해 동일한 포트 개체를 사용할 수 있습니다. 즉, 하나의 스레드에 의해 생성 된 로컬 포트 ​​개체가 다른 스레드에 대한 원격 포트 개체가됩니다.

Listing 3-15 shows the check-in routine of the secondary thread. This method sets up its own local port for future communication and then sends a check-in message back to the main thread. The method uses the port object received in the LaunchThreadWithPort: method as the target of the message.

목록 3-15 체크인 보조 스레드의 루틴을 보여줍니다. 이 방법은 미래의 통신을 위해 자신의 로컬 포트​​를 설정하고 전송 체크인 다시 메인 스레드에 메시지가 표시됩니다.방법은 LaunchThreadWithPort에서 수신 포트 개체를 사용하는 방법 : 메시지의 대상으로.

Listing 3-15  Sending the check-in message using Mach ports

// Worker thread check-in method
- (void)sendCheckinMessage:(NSPort*)outPort
{
    // Retain and save the remote port for future use.
    [self setRemotePort:outPort];
 
    // Create and configure the worker thread port.
    NSPort* myPort = [NSMachPort port];
    [myPort setDelegate:self];
    [[NSRunLoop currentRunLoop] addPort:myPort forMode:NSDefaultRunLoopMode];
 
    // Create the check-in message.
    NSPortMessage* messageObj = [[NSPortMessage alloc] initWithSendPort:outPort
                                         receivePort:myPort components:nil];
 
    if (messageObj)
    {
        // Finish configuring the message and send it immediately.
        [messageObj setMsgId:setMsgid:kCheckinMessage];
        [messageObj sendBeforeDate:[NSDate date]];
    }
}

Configuring an NSMessagePort Object

NSMessagePort 개체 구성

To establish a local connection with an NSMessagePort object, you cannot simply pass port objects between threads. Remote message ports must be acquired by name. Making this possible in Cocoa requires registering your local port with a specific name and then passing that name to the remote thread so that it can obtain an appropriate port object for communication. Listing 3-16 shows the port creation and registration process in cases where you want to use message ports.

NSMessagePort 객체에 로컬 연결을 설정하려면, 당신은 단순히 스레드 사이의 포트 개체를 전달할 수 없습니다. 원격 메시지 포트를 이름으로 취득해야합니다. 코코아이 가능한 만드는 것은 특정 이름으로 로컬 포트​​를 등록 후 통신에 적합한 포트 객체를 취득 할 수 있도록 원격 스레드에 그 이름을 전달해야합니다. 목록 3-16는 메시지 포트를 사용하려는 경우 포트 생성 및 등록 프로세스를 보여줍니다.

Listing 3-16  Registering a message port

NSPort* localPort = [[NSMessagePort alloc] init];
 
// Configure the object and add it to the current run loop.
[localPort setDelegate:self];
[[NSRunLoop currentRunLoop] addPort:localPort forMode:NSDefaultRunLoopMode];
 
// Register the port using a specific name. The name must be unique.
NSString* localPortName = [NSString stringWithFormat:@"MyPortName"];
[[NSMessagePortNameServer sharedInstance] registerPort:localPort
                     name:localPortName];

Configuring a Port-Based Input Source in Core Foundation

코어 재단에 포트 기반 입력 소스 구성

This section shows how to set up a two-way communications channel between your application’s main thread and a worker thread using Core Foundation.

이 섹션에서는 응용 프로그램의 주 스레드와 코어 파운데이션을 사용하여 작업자 스레드 사이에 양방향 통신 채널을 설정하는 방법을 보여줍니다.

Listing 3-17 shows the code called by the application’s main thread to launch the worker thread. The first thing the code does is set up a CFMessagePortRefopaque type to listen for messages from worker threads. The worker thread needs the name of the port to make the connection, so that string value is delivered to the entry point function of the worker thread. Port names should generally be unique within the current user context; otherwise, you might run into conflicts.

목록 3-17 작업자 스레드를 시작하는 응용 프로그램의 주 스레드에 의해 호출 된 코드를 보여줍니다.코드가하는 첫 번째 것은 작업자 스레드에서 메시지를 수신 할 수 CFMessagePortRefopaque 유형을 설정합니다.작업자 스레드가 문자열 값이 작업자 스레드의 진입 점 함수에 전달되도록 연결하려면 포트 이름이 필요합니다. 포트 이름은 일반적으로 현재 사용자 컨텍스트 내에서 고유해야합니다, 그렇지 않으면 당신은 충돌로 실행할 수 있습니다.

Listing 3-17  Attaching a Core Foundation message port to a new thread

#define kThreadStackSize        (8 *4096)
 
OSStatus MySpawnThread()
{
    // Create a local port for receiving responses.
    CFStringRef myPortName;
    CFMessagePortRef myPort;
    CFRunLoopSourceRef rlSource;
    CFMessagePortContext context = {0, NULL, NULL, NULL, NULL};
    Boolean shouldFreeInfo;
 
    // Create a string with the port name.
    myPortName = CFStringCreateWithFormat(NULL, NULL, CFSTR("com.myapp.MainThread"));
 
    // Create the port.
    myPort = CFMessagePortCreateLocal(NULL,
                myPortName,
                &MainThreadResponseHandler,
                &context,
                &shouldFreeInfo);
 
    if (myPort != NULL)
    {
        // The port was successfully created.
        // Now create a run loop source for it.
        rlSource = CFMessagePortCreateRunLoopSource(NULL, myPort, 0);
 
        if (rlSource)
        {
            // Add the source to the current run loop.
            CFRunLoopAddSource(CFRunLoopGetCurrent(), rlSource, kCFRunLoopDefaultMode);
 
            // Once installed, these can be freed.
            CFRelease(myPort);
            CFRelease(rlSource);
        }
    }
 
    // Create the thread and continue processing.
    MPTaskID        taskID;
    return(MPCreateTask(&ServerThreadEntryPoint,
                    (void*)myPortName,
                    kThreadStackSize,
                    NULL,
                    NULL,
                    NULL,
                    0,
                    &taskID));
}

With the port installed and the thread launched, the main thread can continue its regular execution while it waits for the thread to check in. When the check-in message arrives, it is dispatched to the main thread’s MainThreadResponseHandler function, shown in Listing 3-18. This function extracts the port name for the worker thread and creates a conduit for future communication.

포트 설치 및 스레드 시작과 함께, 메인 스레드는 스레드가 체크인하는 것이 기다리는 동안의 정기적 인 실행을 계속하면 체크인이있는 메시지가 도착, 그것은 주 스레드의 MainThreadResponseHandler 함수에 전달됩니다 Listing 3의 수 - 18. 이 기능은 작업자 스레드에 대한 포트 이름을 추출하고 미래의 의사 소통의 통로를 만듭니다.

Listing 3-18  Receiving the checkin message

#define kCheckinMessage 100
 
// Main thread port message handler
CFDataRef MainThreadResponseHandler(CFMessagePortRef local,
                    SInt32 msgid,
                    CFDataRef data,
                    void* info)
{
    if (msgid == kCheckinMessage)
    {
        CFMessagePortRef messagePort;
        CFStringRef threadPortName;
        CFIndex bufferLength = CFDataGetLength(data);
        UInt8* buffer = CFAllocatorAllocate(NULL, bufferLength, 0);
 
        CFDataGetBytes(data, CFRangeMake(0, bufferLength), buffer);
        threadPortName = CFStringCreateWithBytes (NULL, buffer, bufferLength, kCFStringEncodingASCII, FALSE);
 
        // You must obtain a remote message port by name.
        messagePort = CFMessagePortCreateRemote(NULL, (CFStringRef)threadPortName);
 
        if (messagePort)
        {
            // Retain and save the thread’s comm port for future reference.
            AddPortToListOfActiveThreads(messagePort);
 
            // Since the port is retained by the previous function, release
            // it here.
            CFRelease(messagePort);
        }
 
        // Clean up.
        CFRelease(threadPortName);
        CFAllocatorDeallocate(NULL, buffer);
    }
    else
    {
        // Process other messages.
    }
 
    return NULL;
}

With the main thread configured, the only thing remaining is for the newly created worker thread to create its own port and check in. Listing 3-19 shows the entry point function for the worker thread. The function extracts the main thread’s port name and uses it to create a remote connection back to the main thread. The function then creates a local port for itself, installs the port on the thread’s run loop, and sends a check-in message to the main thread that includes the local port name.

주 스레드 구성으로, 남아있는 유일한 것은 새로 만든 작업자 스레드는 자신의 포트를 생성하고 목록 3-19 작업자 스레드의 진입 점 함수를 보여줍니다 체크인 할 수 있습니다. 이 함수는 메인 스레드의 포트 이름을 추출하고 주 스레드에 대한 원격 연결을 다시 만드는 데 사용합니다. 그런 다음이 함수는, 자체 로컬 포트​​를 생성하는 스레드의 실행 루프에 포트를 설치하고 전송 체크인 로컬 포트 ​​이름을 포함하는 주 스레드에 메시지가 표시됩니다.

Listing 3-19  Setting up the thread structures

OSStatus ServerThreadEntryPoint(void* param)
{
    // Create the remote port to the main thread.
    CFMessagePortRef mainThreadPort;
    CFStringRef portName = (CFStringRef)param;
 
    mainThreadPort = CFMessagePortCreateRemote(NULL, portName);
 
    // Free the string that was passed in param.
    CFRelease(portName);
 
    // Create a port for the worker thread.
    CFStringRef myPortName = CFStringCreateWithFormat(NULL, NULL, CFSTR("com.MyApp.Thread-%d"), MPCurrentTaskID());
 
    // Store the port in this thread’s context info for later reference.
    CFMessagePortContext context = {0, mainThreadPort, NULL, NULL, NULL};
    Boolean shouldFreeInfo;
    Boolean shouldAbort = TRUE;
 
    CFMessagePortRef myPort = CFMessagePortCreateLocal(NULL,
                myPortName,
                &ProcessClientRequest,
                &context,
                &shouldFreeInfo);
 
    if (shouldFreeInfo)
    {
        // Couldn't create a local port, so kill the thread.
        MPExit(0);
    }
 
    CFRunLoopSourceRef rlSource = CFMessagePortCreateRunLoopSource(NULL, myPort, 0);
    if (!rlSource)
    {
        // Couldn't create a local port, so kill the thread.
        MPExit(0);
    }
 
    // Add the source to the current run loop.
    CFRunLoopAddSource(CFRunLoopGetCurrent(), rlSource, kCFRunLoopDefaultMode);
 
    // Once installed, these can be freed.
    CFRelease(myPort);
    CFRelease(rlSource);
 
    // Package up the port name and send the check-in message.
    CFDataRef returnData = nil;
    CFDataRef outData;
    CFIndex stringLength = CFStringGetLength(myPortName);
    UInt8* buffer = CFAllocatorAllocate(NULL, stringLength, 0);
 
    CFStringGetBytes(myPortName,
                CFRangeMake(0,stringLength),
                kCFStringEncodingASCII,
                0,
                FALSE,
                buffer,
                stringLength,
                NULL);
 
    outData = CFDataCreate(NULL, buffer, stringLength);
 
    CFMessagePortSendRequest(mainThreadPort, kCheckinMessage, outData, 0.1, 0.0, NULL, NULL);
 
    // Clean up thread data structures.
    CFRelease(outData);
    CFAllocatorDeallocate(NULL, buffer);
 
    // Enter the run loop.
    CFRunLoopRun();
}

Once it enters its run loop, all future events sent to the thread’s port are handled by the ProcessClientRequest function. The implementation of that function depends on the type of work the thread does and is not shown here.

일단 그것의 실행 루프에 들어갑니다, 스레드의 포트로 전송 이후의 모든 이벤트는 ProcessClientRequest 함수에 의해 처리됩니다. 이 기능의 구현은 스레드가 여기에 표시되지 않는 작업의 유형에 따라 달라집니다.

Posted by 창업자닉군
,

Intorduction | About Threaded Programming | Thread Management | Run Loops
Synchronization | Thread Safety Summary | Glossary

본 페이지는 Threading Programming Guide 문서의 Thread Management 부분을 번역해 놓은 페이지 입니다. 발 번역이라 이상한 부분이 있을 수 있습니다. 발견즉시 댓글을 달아 주세요.



Thread Management
스레드 관리

Each process (application) in OS X or iOS is made up of one or more threads, each of which represents a single path of execution through the application's code. Every application starts with a single thread, which runs the application's main function. Applications can spawn additional threads, each of which executes the code of a specific function.

OS X 또는 IOS의 각 프로세스 (응용 프로그램) 응용 프로그램 코드를 통해 실행의 단일 경로를 각각 나타내는 하나 이상의 스레드로 구성됩니다. 모든 응용 프로그램은 응용 프로그램의 주요 기능을 실행하는 단일 스레드로 시작합니다. 응용 프로그램은 특정 함수의 코드를 실행 각각의 추가 스레드를 생성 할 수 있습니다.

When an application spawns a new thread, that thread becomes an independent entity inside of the application's process space. Each thread has its own execution stack and is scheduled for runtime separately by the kernel. A thread can communicate with other threads and other processes, perform I/O operations, and do anything else you might need it to do. Because they are inside the same process space, however, all threads in a single application share the same virtual memory space and have the same access rights as the process itself.

응용 프로그램이 새 스레드를 생성하면 해당 스레드는 응용 프로그램의 프로세스 공간 내부에 독립적 인 엔티티됩니다. 각 스레드는 자신의 실행 스택을 가지고 있으며, 커널이 별도로 런타임 예정이다.스레드는 다른 스레드와 다른 프로세스와 통신 I / O 작업을 수행하고 당신이 할을해야 할 수도 있습니다 다른 작업을 수행 할 수 있습니다. 그들은 동일한 프로세스 공간 내부에 있기 때문에 그러나, 하나의 응용 프로그램의 모든 스레드가 동일한 가상 메모리 공간을 공유하고 프로세스 자체와 동일한 액세스 권한을가집니다.

This chapter provides an overview of the thread technologies available in OS X and iOS along with examples of how to use those technologies in your applications.

이 장에서는 응용 프로그램에서 이러한 기술을 사용하는 방법에 대한 예제와 함께 OS X 및 IOS에서 사용할 수있는 스레드 기술의 개요를 제공합니다.

Thread Costs
스레드 비용

Threading has a real cost to your program (and the system) in terms of memory use and performance. Each thread requires the allocation of memory in both the kernel memory space and your program’s memory space. The core structures needed to manage your thread and coordinate its scheduling are stored in the kernel using wired memory. Your thread’s stack space and per-thread data is stored in your program’s memory space. Most of these structures are created and initialized when you first create the thread—a process that can be relatively expensive because of the required interactions with the kernel.

스레딩 메모리 사용과 성능면에서 프로그램에 실제 비용 (및 시스템)가 있습니다. 각 스레드는 커널 메모리 공간과 프로그램의 메모리 공간 모두에서 메모리 할당이 필요합니다. 귀하의 스레드를 관리하고 일정을 조정하는 데 필요한 핵심 구조는 유선 메모리를 사용하여 커널에 저장됩니다. 귀하의 스레드의 스택 공간과 스레드 당 데이터는 프로그램의 메모리 공간에 저장됩니다. 이러한 구조의 대부분은 생성하고 처음 있기 때문에 커널에 필요한 상호 작용의 상대적으로 비쌀 수 있습니다 스레드 프로세스를 만들 때 초기화됩니다.

Table 2-1 quantifies the approximate costs associated with creating a new user-level thread in your application. Some of these costs are configurable, such as the amount of stack space allocated for secondary threads. The time cost for creating a thread is a rough approximation and should be used only for relative comparisons with each other. Thread creation times can vary greatly depending on processor load, the speed of the computer, and the amount of available system and program memory.

표 2-1는 응용 프로그램에서 새 사용자 수준 스레드를 생성과 관련된 대략적인 비용을 정량화. 이러한 비용 중 일부는 보조 스레드에 할당 된 스택 공간으로 구성 할 수 있습니다.스레드를 만들기위한 시간 비용은 대략적이며, 서로 상대 비교에만 사용되어야한다. 스레드 생성 시간은 프로세서 부하, 컴퓨터의 속도 및 사용 가능한 시스템 및 프로그램 메모리의 양에 따라 크게 달라질 수 있습니다.

Table 2-1  Thread creation costs

Item

Approximate cost

Notes

Kernel data structures

Approximately 1 KB

This memory is used to store the thread data structures and attributes, much of which is allocated as wired memory and therefore cannot be paged to disk.

이 메모리는 유선 메모리를 할당하기 때문에 디스크에 페이징 할 수없는 다량의이 스레드 데이터 구조와 특성을 저장하는 데 사용됩니다.

Stack space

512 KB (secondary threads)

8 MB (OS X main thread)

1 MB (iOS main thread)

The minimum allowed stack size for secondary threads is 16 KB and the stack size must be a multiple of 4 KB. The space for this memory is set aside in your process space at thread creation time, but the actual pages associated with that memory are not created until they are needed.

보조 스레드 허용되는 최소 스택 크기는 16 KB입니다 및 스택 크기는 4 KB를 배수 여야합니다. 이 메모리 공간은 스레드 생성시 프로세스 공간에 따로 설정되어 있지만, 필요할 때까지 메모리 연결된 실제 페이지가 생성되지 않습니다.

Creation time

Approximately 90 microseconds

This value reflects the time between the initial call to create the thread and the time at which the thread’s entry point routine began executing. The figures were determined by analyzing the mean and median values generated during thread creation on an Intel-based iMac with a 2 GHz Core Duo processor and 1 GB of RAM running OS X v10.5.

이 값은 스레드와 스레드의 진입 점 루틴이 실행을 시작하는 시간을 만들기 위해 초기 호출 사이의 시간을 반영합니다.수치는 OS X 10.5을 실행 2 GHz의 코어 듀오 프로세서와 1GB의 RAM과 인텔 기반 아이맥에 스레드를 만드는 동안 생성 된 평균과 중간 값을 분석하여 결정 하였다.

Another cost to consider when writing threaded code is the production costs. Designing a threaded application can sometimes require fundamental changes to the way you organize your application’s data structures. Making those changes might be necessary to avoid the use of synchronization, which can itself impose a tremendous performance penalty on poorly designed applications. Designing those data structures, and debugging problems in threaded code, can increase the time it takes to develop a threaded application. Avoiding those costs can create bigger problems at runtime, however, if your threads spend too much time waiting on locks or doing nothing.

스레드 코드를 작성할 때 고려해야 할 또 다른 비용은 생산 비용이다.스레드 응용 프로그램을 설계하는 것은 때로는 응용 프로그램의 데이터 구조를 구성하는 방식에 근본적인 변화를 요구할 수 있습니다. 이러한 변화를 만드는 것은 그 자체가 잘못 설계된 응용 프로그램에 엄청난 성능 저하를 부과 할 동기의 사용을 방지 할 필요가 있습니다. 이러한 데이터 구조를 설계하고, 스레드 코드의 문제를 디버깅, 그것은 스레드 응용 프로그램을 개발하는 데 소요되는 시간을 늘릴 수 있습니다. 귀하의 스레드가 잠금을 대기하거나 아무것도하지 않고 너무 많은 시간을 소비하는 경우 그 비용을 피하는 것은, 그러나, 런타임에 더 큰 문제를 만들 수 있습니다.

Creating a Thread
스레드 만들기

Creating low-level threads is relatively simple. In all cases, you must have a function or method to act as your thread’s main entry point and you must use one of the available thread routines to start your thread. The following sections show the basic creation process for the more commonly used thread technologies. Threads created using these techniques inherit a default set of attributes, determined by the technology you use. For information on how to configure your threads, see“Configuring Thread Attributes.”

낮은 수준의 스레드를 생성하는 것은 비교적 간단합니다. 모든 경우에, 당신은 기능 또는 스레드의 주 진입 점 역할을하는 방법이 있어야합니다 그리고 당신은 당신의 스레드를 시작하는 데 사용할 수있는 스레드 루틴 중 하나를 사용해야합니다.다음 섹션에서는 일반적으로 사용되는 스레드 기술에 대한 기본 생성 과정을 보여줍니다. 스레드는이 기술을 사용하는 기술에 의해 결정 속성의 기본 세트를 상속하여 만들었습니다. 귀하의 스레드를 구성하는 방법에 대한 자세한 내용은 "스레드 속성 구성"을 참조하십시오.

Using NSThread

NSThread를 사용하여

There are two ways to create a thread using the NSThread class:
NSThread 클래스를 사용하여 스레드를 생성하는 방법은 두 가지가 있습니다 :

  • Use the detachNewThreadSelector:toTarget:withObject: class method to spawn the new thread.
    detachNewThreadSelector를 사용 toTarget : withObject : 새로운 스레드를 생성하는 클래스 메서드.

  • Create a new NSThread object and call its start method. (Supported only in iOS and OS X v10.5 and later.)
    새로운 NSThread 객체를 생성하고 시작 메서드를 호출합니다. (단 IOS 및 OS X 10.5 이상에서만 지원됩니다.)

Both techniques create a detached thread in your application. A detached thread means that the thread’s resources are automatically reclaimed by the system when the thread exits. It also means that your code does not have to join explicitly with the thread later.

두 기술은 응용 프로그램에서 분리 된 스레드를 만들 수 있습니다.분리 된 스레드는 스레드의 리소스가 자동으로 시스템 스레드 종료를 회수하는 것을 의미합니다. 그것은 또한 당신의 코드는 나중에 스레드 명시 적으로 참여하지 않는다는 것을 의미합니다.

Because the detachNewThreadSelector:toTarget:withObject: method is supported in all versions of OS X, it is often found in existing Cocoa applications that use threads. To detach a new thread, you simply provide the name of the method (specified as a selector) that you want to use as the thread’s entry point, the object that defines that method, and any data you want to pass to the thread at startup. The following example shows a basic invocation of this method that spawns a thread using a custom method of the current object.

때문에 detachNewThreadSelector : toTarget : withObject : 방법은 OS X의 모든 버전에서 지원됩니다, 그것은 종종 스레드를 사용하는 기존의 코코아 응용 프로그램에서 찾을 수 있습니다.새 스레드를 분리하려면, 당신은 단순히 당신이 스레드의 진입 점, 해당 메서드를 정의하는 개체로 사용할 메소드의 이름 (선택으로 지정), 당신은 시작할 때 스레드에 전달하려는 모든 데이터를 제공 . 다음 예제에서는 현재 개체의 사용자 지정 메서드를 사용하여 스레드를 생성이 방법의 기본 호출을 보여줍니다.

[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];

Prior to OS X v10.5, you used the NSThread class primarily to spawn threads. Although you could get an NSThread object and access some thread attributes, you could only do so from the thread itself after it was running. In OS X v10.5, support was added for creating NSThread objects without immediately spawning the corresponding new thread. (This support is also available in iOS.) This support made it possible to get and set various thread attributes prior to starting the thread. It also made it possible to use that thread object to refer to the running thread later.

OS X v10.5 이전, 당신은 주로 스레드를 생성하는 NSThread 클래스를 사용했습니다. 당신은 NSThread 객체를 얻을 몇 가지 스레드 속성에 액세스 할 수 있지만 그것을 실행 된 후에, 당신은 단지 스레드 자체에서 그렇게 할 수 있습니다. OS X 10.5에서 지원을 즉시 산란 해당 새 스레드없이 NSThread 객체를 만들기 위해 추가되었습니다. (이 지원은 IOS에서 사용할 수 있습니다.)이 지원이 스레드를 시작에 도착하고 사전에 다양한 스레드 속성을 설정하는 것이 가능했다. 그것은 또한 가능한 나중에 실행중인 스레드를 참조하는 해당 스레드 객체를 사용했다.

The simple way to initialize an NSThread object in OS X v10.5 and later is to use the initWithTarget:selector:object: method. This method takes the exact same information as the detachNewThreadSelector:toTarget:withObject: method and uses it to initialize a new NSThread instance. It does not start the thread, however. To start the thread, you call the thread object’s start method explicitly, as shown in the following example:

선택 : 객체 방법 : OS X 10.5 이상에서 NSThread 객체를 초기화하는 간단한 방법은 initWithTarget를 사용하는 것입니다. toTarget : withObject :이 방법은 detachNewThreadSelector과 정확히 동일한 정보 걸리는 방법을 새로운 NSThread 인스턴스를 초기화하는 데 사용합니다. 그것은 그러나, 스레드를 시작하지 않습니다. 다음 예제와 같이 스레드를 시작하려면, 당신은 명시 적으로 스레드 객체의 start 메소드를 호출

NSThread* myThread = [[NSThread alloc] initWithTarget:self
                                        selector:@selector(myThreadMainMethod:)
                                        object:nil];
[myThread start];  // Actually create the thread

If you have an NSThread object whose thread is currently running, one way you can send messages to that thread is to use theperformSelector:onThread:withObject:waitUntilDone: method of almost any object in your application. Support for performing selectors on threads (other than the main thread) was introduced in OS X v10.5 and is a convenient way to communicate between threads. (This support is also available in iOS.) The messages you send using this technique are executed directly by the other thread as part of its normal run-loop processing. (Of course, this does mean that the target thread has to be running in its run loop; see “Run Loops.”) You may still need some form of synchronization when you communicate this way, but it is simpler than setting up communications ports between the threads.

당신은 누구의 스레드 현재 실행중인 NSThread 객체를 가지고 있다면, 당신은 해당 스레드에 메시지를 보낼 수있는 한 가지 방법은 theperformSelector 사용하는 것입니다 onThread : withObject : waitUntilDone : 응용 프로그램의 거의 모든 객체의 메서드입니다. 스레드 (주 스레드가 아닌)에서 선택기를 수행하기위한 지원 OS X 10.5에서 소개하고 스레드간에 통신 할 수있는 편리한 방법입니다. 한 (이 지원은 IOS에서 사용할 수 있습니다.)이 기술을 사용하여 전송되는 메시지는 정상적인 실행 루프 처리의 일부로서 다른 스레드에서 직접 실행됩니다. 이 방법으로 의사 소통을 할 때 당신은 아직도 동기화의 일부 양식을해야 할 수도 있지만, 통신 포트에게 설정보다 간단합니다; (참조 "실행 루프를."물론,이 타겟 thread의 실행 루프에서 실행해야하는 것을 의미)스레드 사이.

For a list of other thread communication options, see “Setting the Detached State of a Thread.”
다른 thread가 통신 옵션의 목록을 보려면 "스레드의 분리 상태 설정"을 참조하십시오.

Using POSIX Threads

POSIX 스레드를 사용하여

OS X and iOS provide C-based support for creating threads using the POSIX thread API. This technology can actually be used in any type of application (including Cocoa and Cocoa Touch applications) and might be more convenient if you are writing your software for multiple platforms. The POSIX routine you use to create threads is called, appropriately enough, pthread_create.

OS X 및 IOS는 POSIX 스레드 API를 사용하여 스레드를 생성하기위한 C 기반의 지원을 제공합니다. 이 기술은 실제로 모든 유형의 응용 프로그램에서 사용할 수 있습니다 (코코아와 코코아 터치 응용 프로그램 포함) 여러 플랫폼을위한 소프트웨어를 작성하는 경우 더 편리 할 수 있습니다. 스레드를 만드는 데 사용하는 POSIX 루틴가 pthread_create, 적절하게 충분히이라고합니다.

Listing 2-1 shows two custom functions for creating a thread using POSIX calls. The LaunchThread function creates a new thread whose main routine is implemented in the PosixThreadMainRoutine function. Because POSIX creates threads as joinable by default, this example changes the thread’s attributes to create a detached thread. Marking the thread as detached gives the system a chance to reclaim the resources for that thread immediately when it exits.

목록 2-1 POSIX 호출을 사용하여 스레드를 생성하기위한 두 개의 사용자 지정 함수를 보여줍니다.LaunchThread 함수는 누구의 주요 루틴 PosixThreadMainRoutine 함수에서 구현되는 새로운 스레드를 만듭니다. POSIX는 기본적으로 조인으로 스레드를 생성하기 때문에이 예제는 분리 된 스레드를 생성하는 스레드의 속성을 변경합니다. 분리로 스레드를 표시하면 시스템에게이 스레드 리소스를 확보 할 수있는 기회를 제공 곧바로 때 종료됩니다.

Listing 2-1  Creating a thread in C

#include <assert.h>
#include <pthread.h>
 
void* PosixThreadMainRoutine(void* data)
{
    // Do some work here.
 
    return NULL;
}
 
void LaunchThread()
{
    // Create the thread using POSIX routines.
    pthread_attr_t  attr;
    pthread_t       posixThreadID;
    int             returnVal;
 
    returnVal = pthread_attr_init(&attr);
    assert(!returnVal);
    returnVal = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    assert(!returnVal);
 
    int     threadError = pthread_create(&posixThreadID, &attr, &PosixThreadMainRoutine, NULL);
 
    returnVal = pthread_attr_destroy(&attr);
    assert(!returnVal);
    if (threadError != 0)
    {
         // Report an error.
    }
}

If you add the code from the preceding listing to one of your source files and call the LaunchThread function, it would create a new detached thread in your application. Of course, new threads created using this code would not do anything useful. The threads would launch and almost immediately exit. To make things more interesting, you would need to add code to the PosixThreadMainRoutine function to do some actual work. To ensure that a thread knows what work to do, you can pass it a pointer to some data at creation time. You pass this pointer as the last parameter of the pthread_create function.

당신은 위의 목록에서 소스 파일 중 하나에 코드를 추가 LaunchThread의 함수를 호출하면 응용 프로그램에서 새로운 분리 된 스레드를 만듭니다. 물론,이 코드를 사용하여 만든 새 스레드 유용한 아무것도하지 않을 것입니다.스레드가 시작하고 거의 즉시 종료됩니다. 상황이 더 흥미로운 만들기 위해, 당신은 몇 가지 실제 작업을 수행 할 PosixThreadMainRoutine 함수에 코드를 추가해야합니다.스레드가 할 일이 무엇을 알고 있는지 확인하려면, 당신은 그것을 생성시 일부 데이터에 대한 포인터를 전달할 수 있습니다. 당신은가 pthread_create 함수의 마지막 매개 변수로이 포인터를 전달합니다.

To communicate information from your newly created thread back to your application’s main thread, you need to establish a communications path between the target threads. For C-based applications, there are several ways to communicate between threads, including the use of ports, conditions, or shared memory. For long-lived threads, you should almost always set up some sort of inter-thread communications mechanism to give your application’s main thread a way to check the status of the thread or shut it down cleanly when the application exits.

응용 프로그램의 주 스레드에 새로 생성 된 스레드를 다시에서 정보를 전달하기 위해, 당신은 대상 스레드 간의 통신 경로를 설정해야합니다. C 기반 응용 프로그램, 포트, 조건, 또는 공유 메모리의 사용을 포함하여 스레드간에 통신하는 방법에는 여러 가지가 있습니다. 수명이 긴 스레드, 당신은 거의 항상 스레드 간 통신의 일종 응용 프로그램의 주 스레드에게 스레드의 상태를 확인하거나 응용 프로그램이 종료 할 때 청결하게 종료하는 방법을 제공하는 메커니즘을 설정해야합니다.

For more information about POSIX thread functions, see the pthread man page.
POSIX 쓰레드 함수에 대한 자세한 내용은 pthread에 매뉴얼 페이지를 참조하십시오.

Using NSObject to Spawn a Thread

스레드를 생성하는 NSObject의 사용

In iOS and OS X v10.5 and later, all objects have the ability to spawn a new thread and use it to execute one of their methods. TheperformSelectorInBackground:withObject: method creates a new detached thread and uses the specified method as the entry point for the new thread. For example, if you have some object (represented by the variable myObj) and that object has a method called doSomething that you want to run in a background thread, you could use the following code to do that:

IOS 나중에 OS X 10.5 이상에서는 모든 개체는 새로운 스레드를 생성하고 해당 메서드 중 하나를 실행하는 데 사용하는 기능이 있습니다. TheperformSelectorInBackground : withObject : 메서드는 새로운 분리 된 스레드를 생성하고 새 스레드의 진입 점으로 지정된 메서드를 사용합니다. 당신은 어떤 객체 (변수하여 MyObj로 표현)가 있고 그 객체는 백그라운드 스레드에서 실행하려는 해봐요라는 메서드가있는 경우 예를 들어, 당신은 그렇게 할 다음 코드를 사용할 수 있습니다 :

[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];

The effect of calling this method is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object, selector, and parameter object as parameters. The new thread is spawned immediately using the default configuration and begins running. Inside the selector, you must configure the thread just as you would any thread. For example, you would need to set up an autorelease pool (if you were not using garbage collection) and configure the thread’s run loop if you planned to use it. For information on how to configure new threads, see “Configuring Thread Attributes.”

당신이 detachNewThreadSelector를 호출하면이 메소드를 호출의 효과는 동일합니다 toTarget : withObject : 현재 개체를 선택하고 매개 변수로 매개 변수 개체를 NSThread의 방법.새 스레드는 기본 구성을 사용하여 즉시 양산 및 실행을 시작합니다.선택 안에, 당신은 당신이 어떤 스레드와 마찬가지로 스레드를 구성해야합니다. 예를 들어, autorelease를 풀 (당신은 가비지 수집을 사용하지 않은 경우)을 설정하고 당신이 그것을 사용하는 계획하는 경우 스레드의 실행 루프를 구성해야합니다. 새 스레드를 구성하는 방법에 대한 자세한 내용은 "스레드 속성 구성"을 참조하십시오.

Using POSIX Threads in a Cocoa Application

코코아 응용 프로그램에서 POSIX 스레드를 사용하여

Although the NSThread class is the main interface for creating threads in Cocoa applications, you are free to use POSIX threads instead if doing so is more convenient for you. For example, you might use POSIX threads if you already have code that uses them and you do not want to rewrite it. If you do plan to use the POSIX threads in a Cocoa application, you should still be aware of the interactions between Cocoa and threads and obey the guidelines in the following sections.

NSThread 클래스는 코코아 응용 프로그램에서 스레드를 생성하기위한 주요 인터페이스이지만, 당신은 이렇게하면 당신을 위해 더 편리한 경우 대신 POSIX 스레드를 사용하여 무료입니다. 당신이 이미 그들을 사용하는 코드를 가지고 당신이 그것을 다시하지 않으려면 예를 들어, POSIX 스레드를 사용할 수 있습니다. 당신은 코코아 응용 프로그램에서 POSIX 스레드를 사용하여 계획을 할 경우, 당신은 여전히 ​​코코아와 스레드 간의 상호 작용을 인식하고 다음 섹션의 지침을 준수해야합니다.

Protecting the Cocoa Frameworks
코코아 프레임 워크를 보호

For multithreaded applications, Cocoa frameworks use locks and other forms of internal synchronization to ensure they behave correctly. To prevent these locks from degrading performance in the single-threaded case, however, Cocoa does not create them until the application spawns its first new thread using the NSThreadclass. If you spawn threads using only POSIX thread routines, Cocoa does not receive the notifications it needs to know that your application is now multithreaded. When that happens, operations involving the Cocoa frameworks may destabilize or crash your application.

다중 스레드 응용 프로그램의 경우, 코코아 프레임 워크들이 제대로 동작하기 위해 잠금 및 내부 동기화의 다른 형태를 사용합니다. 응용 프로그램이 NSThreadclass를 사용하여 먼저 새로운 스레드를 생성 할 때까지 단일 스레드의 경우 성능 저하에서 이러한 잠금을 방지하기 위해, 그러나, 코코아를 작성하지 않습니다. 당신은 POSIX 스레드 루틴을 사용하여 스레드를 생성하는 경우, 코코아는 응용 프로그램이 다중 스레드 것을 알 필요가 알림을받지 않습니다. 그렇게되면, 코코아 프레임 워크와 관련된 작업은 응용 프로그램을 불안정하거나 중단 될 수 있습니다.

To let Cocoa know that you intend to use multiple threads, all you have to do is spawn a single thread using the NSThread class and let that thread immediately exit. Your thread entry point need not do anything. Just the act of spawning a thread using NSThread is enough to ensure that the locks needed by the Cocoa frameworks are put in place.

코코아는 여러 스레드를 사용하고자하는 알 수 있도록, 당신이해야 할 모든 NSThread 클래스를 사용하여 단일 스레드를 생성하고 스레드가 즉시 종료하게됩니다. 귀하의 스레드 엔트리 포인트는 아무것도 할 필요가 없습니다. 산란 단지 행위는 NSThread를 사용하여 스레드는 코코아 프레임 워크에 필요한 잠금 위치에 배치되어 있는지 확인하기 위해 충분하다.

If you are not sure if Cocoa thinks your application is multithreaded or not, you can use the isMultiThreaded method of NSThread to check.

코코아 응용 프로그램이 다중 스레드인지 생각하면 당신이 확실하지 않은 경우, 당신은 확인 NSThread의 isMultiThreaded 방법을 사용할 수 있습니다.

Mixing POSIX and Cocoa Locks

POSIX와 코코아 잠금을 혼합

It is safe to use a mixture of POSIX and Cocoa locks inside the same application. Cocoa lock and condition objects are essentially just wrappers for POSIX mutexes and conditions. For a given lock, however, you must always use the same interface to create and manipulate that lock. In other words, you cannot use a CocoaNSLock object to manipulate a mutex you created using the pthread_mutex_init function, and vice versa.

같은 응용 프로그램 내에서 POSIX와 코코아 락의 혼합물을 사용하는 것이 안전하다. 코코아 잠금 상태 객체는 본질적으로 POSIX 뮤텍스와 조건에 대한 래퍼입니다. 주어진 잠금, 그러나, 당신은 항상 잠금을 생성하고 조작하는 동일한 인터페이스를 사용해야합니다. 즉, 당신은 당신이 pthread_mutex_init는 함수를 사용하여 만든 뮤텍스 반대를 조작 할 수 CocoaNSLock 개체를 사용할 수 없습니다.

Configuring Thread Attributes
스레드 속성 구성

After you create a thread, and sometimes before, you may want to configure different portions of the thread environment. The following sections describe some of the changes you can make and when you might make them.
당신이 스레드를 생성하고, 때로는 이전 후에는 스레드 환경의 다른 부분을 구성 할 수 있습니다.다음 섹션에서는 당신이 할 수있는 변경 사항 중 일부를 설명하고 당신이 그 (것)들을 만들 수있는 경우에.

Configuring the Stack Size of a Thread

스레드의 스택 크기 구성

For each new thread you create, the system allocates a specific amount of memory in your process space to act as the stack for that thread. The stack manages the stack frames and is also where any local variables for the thread are declared. The amount of memory allocated for threads is listed in “Thread Costs.”

당신이 만든 각 새 스레드를 들어, 시스템은 해당 스레드에 대한 스택 역할을 프로세스 공간에서 특정 양의 메모리를 할당합니다.스택은 스택 프레임을 관리하고 스레드 로컬 변수가 선언 된 곳도있다. 스레드에 할당 된 메모리의 양에 나와있는 "스레드 비용."

If you want to change the stack size of a given thread, you must do so before you create the thread. All of the threading technologies provide some way of setting the stack size, although setting the stack size using NSThread is available only in iOS and OS X v10.5 and later. Table 2-2 lists the different options for each technology.

당신은 지정된 스레드의 스택 크기를 변경하려는 경우에는 스레드를 작성하기 전에, 당신은 그렇게해야합니다. NSThread를 사용하여 스택 크기를 설정하면 전용 IOS하고 OS X 10.5 이상에서만 사용할 수 있지만 스레딩 기술의 모든, 스택 크기를 설정하는 몇 가지 방법을 제공합니다. 표 2-2은 각 기술에 대한 다른 옵션을 나열합니다.

Table 2-2  Setting the stack size of a thread

Technology

Option

Cocoa

In iOS and OS X v10.5 and later, allocate and initialize an NSThread object (do not use thedetachNewThreadSelector:toTarget:withObject: method). Before calling the start method of the thread object, use thesetStackSize: method to specify the new stack size.

IOS 및 OS X 10.5 이상에서 할당하고 NSThread 객체 (thedetachNewThreadSelector 사용하지 마십시오 toTarget : withObject : 방법)을 초기화합니다.스레드 객체의 start 메소드를 호출하기 전에, thesetStackSize를 사용하는 방법 : 새 스택 크기를 지정합니다.

POSIX

Create a new pthread_attr_t structure and use the pthread_attr_setstacksize function to change the default stack size. Pass the attributes to the pthread_create function when creating your thread.

새로운 위해서는 pthread_attr_t 구조를 생성하고 기본 스택 크기를 변경하려면 pthread_attr_setstacksize 함수를 사용합니다. 귀하의 스레드를 생성 할 때가 pthread_create 함수에 속성을 전달합니다.

Multiprocessing Services

Pass the appropriate stack size value to the MPCreateTask function when you create your thread.
당신의 스레드를 만들 MPCreateTask 기능에 대한 적절한 스택 크기 값을 전달합니다.

Configuring Thread-Local Storage

스레드 로컬 저장소 구성

Each thread maintains a dictionary of key-value pairs that can be accessed from anywhere in the thread. You can use this dictionary to store information that you want to persist throughout the execution of your thread. For example, you could use it to store state information that you want to persist through multiple iterations of your thread’s run loop.

각 스레드는 어디 스레드에서 액세스 할 수있는 키 - 값 쌍의 사전을 유지합니다. 당신은 당신의 스레드의 실행을 통해 유지하고자하는 정보를 저장하기 위해이 사전을 사용할 수 있습니다. 예를 들어, 당신은 당신의 스레드의 실행 루프를 여러 번 반복을 통해 유지하려는 상태 정보를 저장하는 데 사용할 수 있습니다.

Cocoa and POSIX store the thread dictionary in different ways, so you cannot mix and match calls to the two technologies. As long as you stick with one technology inside your thread code, however, the end results should be similar. In Cocoa, you use the threadDictionary method of an NSThread object to retrieve anNSMutableDictionary object, to which you can add any keys required by your thread. In POSIX, you use the pthread_setspecific and pthread_getspecificfunctions to set and get the keys and values of your thread.

코코아와 POSIX 저장 다른 방법으로 스레드 사전, 그래서 당신은 혼합 두 기술에 대한 호출을 일치시킬 수 없습니다. 로 당신이 당신의 스레드 코드 내부에 하나의 기술을 스틱으로, 그러나 최종 결과는 ​​비슷해야합니다. 코코아, 당신은 anNSMutableDictionary 개체를 검색 할에 당신의 스레드에 필요한 키를 추가 할 수 있습니다 NSThread 객체의 threadDictionary 메서드를 사용합니다. POSIX에서, 당신은 당신의 스레드의 키와 값을 설정하고 가져 pthread_setspecific 및 pthread_getspecificfunctions를 사용합니다.

Setting the Detached State of a Thread

스레드의 분리 상태 설정

Most high-level thread technologies create detached threads by default. In most cases, detached threads are preferred because they allow the system to free up the thread’s data structures immediately upon completion of the thread. Detached threads also do not require explicit interactions with your program. The means of retrieving results from the thread is left to your discretion. By comparison, the system does not reclaim the resources for joinable threads until another thread explicitly joins with that thread, a process which may block the thread that performs the join.

가장 높은 수준의 스레드 기술은 기본적으로 분리 된 스레드를 만들 수 있습니다. 그들은 시스템이 스레드의 완료 즉시 스레드의 데이터 구조를 확보 할 수 있기 때문에 대부분의 경우, 분리 된 스레드가 바람직하다. 분리 된 스레드는 프로그램에 명시 적으로 상호 작용을 필요로하지 않습니다.스레드에서 결과를 검색하는 방법은 재량에 남아 있습니다. 다른 스레드가 명시 적으로 해당 스레드와 조인을 수행하는 스레드를 차단할 수있는 프로세스를 조인 할 때까지 비교함으로써, 시스템이 결합 가능한 스레드 자원을 재생하지 않습니다.

You can think of joinable threads as akin to child threads. Although they still run as independent threads, a joinable thread must be joined by another thread before its resources can be reclaimed by the system. Joinable threads also provide an explicit way to pass data from an exiting thread to another thread. Just before it exits, a joinable thread can pass a data pointer or other return value to the pthread_exit function. Another thread can then claim this data by calling the pthread_joinfunction.

당신은 자식 스레드에 가깝다으로 결합 가능한 스레드를 생각할 수 있습니다. 그들은 여전히 ​​독립적 인 스레드로 실행되지만 자원이 시스템에 의해 회수 될 수 있기 전에, 조인 스레드가 다른 스레드에 가입해야합니다. 결합 가능한 스레드는 다른 스레드 종료 스레드에서 데이터를 전달하는 명시적인 방법을 제공합니다. 그냥 종료되기 전에, 조인 스레드는 데이터 포인터 또는 pthread_exit 함수에 다른 반환 값을 전달할 수 있습니다. 다른 스레드는 pthread_joinfunction를 호출하여이 데이터를 청구 할 수 있습니다.

If you do want to create joinable threads, the only way to do so is using POSIX threads. POSIX creates threads as joinable by default. To mark a thread as detached or joinable, modify the thread attributes using the pthread_attr_setdetachstate function prior to creating the thread. After the thread begins, you can change a joinable thread to a detached thread by calling the pthread_detach function. For more information about these POSIX thread functions, see the pthread man page. For information on how to join with a thread, see the pthread_join man page.

당신이 결합 가능한 스레드를 생성 할 경우, 그렇게 할 수있는 유일한 방법은 POSIX 스레드를 사용하고 있습니다. POSIX는 기본적으로 조인으로 스레드를 만듭니다. 분리 또는 조인과 같은 스레드를 표시하려면 스레드는 이전 스레드를 만드는 pthread_attr_setdetachstate 기능을 사용하여 속성을 수정합니다. 스레드가 시작되면, 당신은에 pthread_detach 함수를 호출하여 분리 된 스레드에 결합 가능한 스레드를 변경할 수 있습니다. 이러한 POSIX 쓰레드 함수에 대한 자세한 내용은 pthread에 매뉴얼 페이지를 참조하십시오.스레드와 조인하는 방법에 대한 자세한 내용까지 pthread_join 매뉴얼 페이지를 참조하십시오.

Setting the Thread Priority

스레드 우선 순위 설정

Any new thread you create has a default priority associated with it. The kernel’s scheduling algorithm takes thread priorities into account when determining which threads to run, with higher priority threads being more likely to run than threads with lower priorities. Higher priorities do not guarantee a specific amount of execution time for your thread, just that it is more likely to be chosen by the scheduler when compared to lower-priority threads.

당신이 만드는 모든 새 스레드와 연관된 기본 우선 순위가 있습니다. 실행하는 스레드를 결정할 때 커널의 스케줄링 알고리즘은 우선 순위가 높은 쓰레드가 낮은 우선 순위를 가진 스레드보다 실행 가능성이되는, 계정에 스레드 우선 순위를 사용합니다. 높은 우선 순위는 우선 순위가 낮은 스레드에 비해 스케줄러에 의해 선택 될 가능성이 높습니다 그냥 당신의 스레드에 대한 실행 시간의 특정 금액을 보장하지 않습니다.

If you do want to modify thread priorities, both Cocoa and POSIX provide a way to do so. For Cocoa threads, you can use the setThreadPriority: class method ofNSThread to set the priority of the currently running thread. For POSIX threads, you use the pthread_setschedparam function. For more information, seeNSThread Class Reference or pthread_setschedparam man page.

당신이 스레드 우선 순위를 변경하려는 경우, 코코아 및 POSIX 모두 그렇게 할 수있는 방법을 제공합니다. 코코아 스레드, 당신은 setThreadPriority을 사용할 수 있습니다 : 클래스 메소드 ofNSThread을 현재 실행중인 스레드의 우선 순위를 설정합니다. POSIX 쓰레드를 들어, 당신은 pthread_setschedparam 기능을 사용합니다. 자세한 내용은 seeNSThread 클래스 참조 또는 pthread_setschedparam 매뉴얼 페이지에 대한.

Writing Your Thread Entry Routine
귀하의 스레드 입력 루틴을 작성

For the most part, the structure of your thread’s entry point routines is the same in OS X as it is on other platforms. You initialize your data structures, do some work or optionally set up a run loop, and clean up when your thread’s code is done. Depending on your design, there may be some additional steps you need to take when writing your entry routine.

그것은 다른 플랫폼이기 때문에 대부분의 경우, 사용자 스레드의 진입 점 루틴의 구조는 OS X에서 동일합니다. 당신은 당신의 데이터 구조를 초기화하는 몇 가지 작업을 수행하거나 선택적으로 실행 루프를 설정하고 스레드의 코드가 완료되면 정리. 당신의 디자인에 따라, 당신은 항목 루틴을 작성할 때 취할 필요가 몇 가지 추가 단계가있을 수 있습니다.

Creating an Autorelease Pool

오토 릴리스 풀 만들기

Applications that link in Objective-C frameworks typically must create at least one autorelease pool in each of their threads. If an application uses the managed model—where the application handles the retaining and releasing of objects—the autorelease pool catches any objects that are autoreleased from that thread.

오브젝티브-C 프레임 워크에있는 링크는 일반적으로 해당 스레드 각각에 적어도 하나 autorelease를 풀을 만들어야합니다하는 응용 프로그램.응용 프로그램을 사용하는 경우 응용 프로그램의 유지 및 해제 처리 모델 위치 관리 객체를 autorelease를 풀 그 스레드에서 autoreleased 된 개체를 잡는다.

If an application uses garbage collection instead of the managed memory model, creation of an autorelease pool is not strictly necessary. The presence of an autorelease pool in a garbage-collected application is not harmful, and for the most part is simply ignored. It is allowed for cases where a code module must support both garbage collection and the managed memory model. In such a case, the autorelease pool must be present to support the managed memory model code and is simply ignored if the application is run with garbage collection enabled.

응용 프로그램이 대신 관리되는 메모리 모델의 가비지 수집을 사용하는 경우 autorelease를 풀의 생성은 꼭 필요하지 않습니다.가비지 수집 응용 프로그램에서 autorelease를 풀의 존재는 유해하지 않고, 대부분의 경우 단순히 무시됩니다. 이 코드 모듈 가비지 수집 및 관리되는 메모리 모델을 모두 지원해야하는 경우에 허용된다. 이러한 경우, autorelease를 풀은 관리되는 메모리 모델 코드를 지원하기 위해 존재해야하고 응용 프로그램을 사용할 가비지 컬렉션을 실행하면 간단하게 무시됩니다.

If your application uses the managed memory model, creating an autorelease pool should be the first thing you do in your thread entry routine. Similarly, destroying this autorelease pool should be the last thing you do in your thread. This pool ensures that autoreleased objects are caught, although it does not release them until the thread itself exits. Listing 2-2 shows the structure of a basic thread entry routine that uses an autorelease pool.

응용 프로그램이 작성, 관리되는 메모리 모델을 사용하는 경우 autorelease를 풀은 당신의 스레드 입력 루틴에서 할 첫 번째 일은해야한다. 마찬가지로,이 autorelease를 풀을 파괴하는 것은 당신의 스레드에서 수행 할 마지막 일이 될 것이다. 이 풀은 스레드 자체가 종료 될 때까지 해제되지 않지만 autoreleased 개체가 발견되어 있는지 확인합니다. 목록 2-2 autorelease를 풀을 사용하여 기본 스레드 입력 루틴의 구조를 보여줍니다.

Listing 2-2  Defining your thread entry point routine

- (void)myThreadMainRoutine
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Top-level pool
 
    // Do thread work here.
 
    [pool release];  // Release the objects in the pool.
}

Because the top-level autorelease pool does not release its objects until the thread exits, long-lived threads should create additional autorelease pools to free objects more frequently. For example, a thread that uses a run loop might create and release an autorelease pool each time through that run loop. Releasing objects more frequently prevents your application’s memory footprint from growing too large, which can lead to performance problems. As with any performance-related behavior though, you should measure the actual performance of your code and tune your use of autorelease pools appropriately.

최상위 autorelease를 풀 스레드가 종료 될 때까지 해당 개체를 해제하지 않기 때문에, 수명이 긴 스레드가 더 자주 무료 오브젝트에 추가 autorelease를 풀을 만들어야합니다. 예를 들어, 실행 루프를 사용하여 스레드가 실행되는 루프를 통해 매번 생성하고 autorelease를 풀을 해제 할 수 있습니다. 객체를 해제하면 더 자주 성능 문제로 이어질 수있는, 너무 큰 성장에서 응용 프로그램의 메모리 풋 프린트를 방지 할 수 있습니다. 하지만 모든 성능 관련 문제와 마찬가지로, 당신은 당신의 코드의 실제 성능을 측정하고 적절하게 autorelease를 풀의 사용을 조정해야합니다.

For more information on memory management and autorelease pools, see Advanced Memory Management Programming Guide.
메모리 관리 및 autorelease를 풀에 대한 자세한 내용은 고급 메모리 관리 프로그래밍 가이드를 참조하십시오.

Setting Up an Exception Handler

예외 처리기를 설정

If your application catches and handles exceptions, your thread code should be prepared to catch any exceptions that might occur. Although it is best to handle exceptions at the point where they might occur, failure to catch a thrown exception in a thread causes your application to exit. Installing a final try/catch in your thread entry routine allows you to catch any unknown exceptions and provide an appropriate response.

응용 프로그램이 예외를 catch 및 처리하는 경우 스레드 코드가 발생할 수있는 모든 예외를 catch 할 준비가되어 있어야합니다. 그것은 그들이 발생할 수 있습니다 점에서 예외를 처리하는 것이 가장 좋지만, 스레드에서 throw 된 예외를 catch하지 못하면 응용 프로그램이 종료됩니다. 귀하의 스레드 진입 루틴에서 try / catch를 최종 설치를하면 알 수없는 예외를 catch하고 적절한 응답을 제공 할 수 있습니다.

You can use either the C++ or Objective-C exception handling style when building your project in Xcode. For information about setting how to raise and catch exceptions in Objective-C, see Exception Programming Topics.

엑스 코드에서 프로젝트를 빌드 할 때는 C + + 또는 목표-C 예외 처리 스타일을 사용할 수 있습니다. 인상 및 목표-C에서 예외를 잡아 예외 프로그래밍 항목을 참조하는 방법을 설정하는 방법에 대한 자세한 내용은 다음을 참조하십시오.

Setting Up a Run Loop

실행 루프를 설정

When writing code you want to run on a separate thread, you have two options. The first option is to write the code for a thread as one long task to be performed with little or no interruption, and have the thread exit when it finishes. The second option is put your thread into a loop and have it process requests dynamically as they arrive. The first option requires no special setup for your code; you just start doing the work you want to do. The second option, however, involves setting up your thread’s run loop.

당신이 별도의 스레드에서 실행하려면 코드를 작성할 때, 당신은 두 가지 옵션이 있습니다.첫 번째 옵션은 하나의 긴 작업이 거의 중단없이 수행 할 수로 스레드 코드를 작성하고 완료되면 스레드 종료하는 것입니다.두 번째 옵션은 루프로 스레드를 넣고 그들이 도착 동적으로 요청을 처리해야합니다.첫 번째 옵션은 코드에 대한 특별한 설정을 필요로하지 않습니다, ​​당신은 당신이하고 싶은 일을 시작합니다. 두 번째 옵션은, 그러나 스레드의 실행 루프를 설정하는 것과 관련되어 있습니다.

OS X and iOS provide built-in support for implementing run loops in every thread. The app frameworks start the run loop of your application’s main thread automatically. If you create any secondary threads, you must configure the run loop and start it manually.

OS X 및 IOS는 모든 스레드에서 실행 루프를 구현하기위한 기본적으로 지원합니다.응용 프로그램 프레임 워크가 자동으로 응용 프로그램의 주 스레드의 실행 루프를 시작합니다. 당신은 어떤 보조 스레드를 만들 경우 실행 루프를 구성하고 수동으로 시작해야합니다.

For information on using and configuring run loops, see “Run Loops.”
실행 루프를 사용 및 구성에 대한 자세한 내용은 "실행 루프"를 참조하십시오.

Terminating a Thread
스레드 종료

The recommended way to exit a thread is to let it exit its entry point routine normally. Although Cocoa, POSIX, and Multiprocessing Services offer routines for killing threads directly, the use of such routines is strongly discouraged. Killing a thread prevents that thread from cleaning up after itself. Memory allocated by the thread could potentially be leaked and any other resources currently in use by the thread might not be cleaned up properly, creating potential problems later.

스레드를 종료하기 위해 권장되는 방법은 일반적으로의 진입 점 루틴을 종료하도록하는 것입니다. 코코아, POSIX 및 멀티 프로세싱 서비스 직접 스레드를 죽이는 루틴을 제공하지만, 이러한 루틴의 사용을 강력하게 권장합니다.스레드를 죽이는 것은 자신 후에 청소에서 해당 스레드를 방지 할 수 있습니다.스레드에 의해 할당 된 메모리는 잠재적으로 유출 될 수있는 현재 스레드에서 사용하는 다른 자원은 나중에 잠재적 인 문제를 만들고 제대로 정리되지 않을 수 있습니다.

If you anticipate the need to terminate a thread in the middle of an operation, you should design your threads from the outset to respond to a cancel or exit message. For long-running operations, this might mean stopping work periodically and checking to see if such a message arrived. If a message does come in asking the thread to exit, the thread would then have the opportunity to perform any needed cleanup and exit gracefully; otherwise, it could simply go back to work and process the next chunk of data.

당신이 작업의 중간에 스레드를 종료 할 필요가 예상되는 경우, 당신은 취소에 응답하거나 메시지를 종료하려면 처음부터 당신의 스레드를 설계해야합니다. 장기 실행 작업의 경우,이 주기적으로 작업을 중지하고 메시지가 도착하는지 확인하는 검사를 의미 할 수 있습니다.메시지를 종료 할 스레드를 물어 올 경우, 스레드는 필요한 모든 정리 작업을 수행하고 정상적으로 종료 할 수있는 기회를 가질 것입니다, 그렇지 않으면 단순히 일하러 가서 데이터의 다음 청크를 처리 할 수 있습니다.

One way to respond to cancel messages is to use a run loop input source to receive such messages. Listing 2-3 shows the structure of how this code might look in your thread’s main entry routine. (The example shows the main loop portion only and does not include the steps for setting up an autorelease pool or configuring the actual work to do.) The example installs a custom input source on the run loop that presumably can be messaged from another one of your threads; for information on setting up input sources, see “Configuring Run Loop Sources.” After performing a portion of the total amount of work, the thread runs the run loop briefly to see if a message arrived on the input source. If not, the run loop exits immediately and the loop continues with the next chunk of work. Because the handler does not have direct access to the exitNow local variable, the exit condition is communicated through a key-value pair in the thread dictionary.

메시지를 취소하려면 대응하는 한 가지 방법은 메시지를 수신 런 루프 입력 소스를 사용하는 것입니다. 목록 2-3이 코드가 스레드의 주 진입 루틴에서 볼 수있는 방법의 구조를 보여줍니다. (예제는 메인 루프 부분을 보여줍니다 autorelease를 풀을 설정하거나 할 수있는 실제 작업을 구성하는 단계를 포함하지 않습니다.) 예제는 아마도 또 다른 하나의 메세지를 할 수있는 실행 루프에 사용자 정의 입력 소스를 설치 귀하의 스레드, 입력 소스를 설정하는 방법에 대한 자세한 내용은 "실행 루프 소스 구성"을 참조하십시오. 작업의 총 금액의 일부를 수행 한 후 스레드가 메시지가 입력 소스에 도착하는지 간단히 실행 루프를 실행합니다. 그렇지 않은 경우, 즉시 실행 루프가 종료되고 루프 작업의 다음 청크를 계속합니다. 핸들러가 exitNow 로컬 변수에 직접 액세스 할 수 없기 때문에, 종료 상태는 스레드 사전의 키 - 값 쌍을 통해 전달됩니다.

Listing 2-3  Checking for an exit condition during a long job

- (void)threadMainRoutine
{
    BOOL moreWorkToDo = YES;
    BOOL exitNow = NO;
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
 
    // Add the exitNow BOOL to the thread dictionary.
    NSMutableDictionary* threadDict = [[NSThread currentThread] threadDictionary];
    [threadDict setValue:[NSNumber numberWithBool:exitNow] forKey:@"ThreadShouldExitNow"];
 
    // Install an input source.
    [self myInstallCustomInputSource];
 
    while (moreWorkToDo && !exitNow)
    {
        // Do one chunk of a larger body of work here.
        // Change the value of the moreWorkToDo Boolean when done.
 
        // Run the run loop but timeout immediately if the input source isn't waiting to fire.
        [runLoop runUntilDate:[NSDate date]];
 
        // Check to see if an input source handler changed the exitNow value.
        exitNow = [[threadDict valueForKey:@"ThreadShouldExitNow"] boolValue];
    }
}

Posted by 창업자닉군
,

Intorduction | About Threaded Programming | Thread Management | Run Loops
Synchronization | Thread Safety Summary | Glossary

본 페이지는 Threading Programming Guide 문서의 About Threaded Programming 부분을 번역해 놓은 페이지 입니다. 발 번역이라 이상한 부분이 있을 수 있습니다. 발견즉시 댓글을 달아 주세요.


About Threaded Programming
쓰레드 프로그래밍에 관해서

For many years, maximum computer performance was limited largely by the speed of a single microprocessor at the heart of the computer. As the speed of individual processors started reaching their practical limits, however, chip makers switched to multicore designs, giving the computer the opportunity to perform multiple tasks simultaneously. And although OS X takes advantage of these cores whenever it can to perform system-related tasks, your own applications can also take advantage of them through threads.

많은 년간, 최대 컴퓨터 성능은 컴퓨터의 중심에 하나의 마이크로 프로세서의 속도에 의해 크게 제한되었다. 각 프로세서의 속도가 실제 한계에 도달하기 시작으로, 그러나, 칩 제조업체는 컴퓨터에게 동시에 여러 작업을 수행 할 수있는 기회를 제공, 설계를 멀티 코어로 전환. 때마다 시스템 관련 작업을 수행 할 수있는 OS X이 코어를 활용하지만, 당신의 자신의 응용 프로그램은 스레드를 통해 활용할 수 있습니다.

What Are Threads?
쓰레드는 무엇인가?

Threads are a relatively lightweight way to implement multiple paths of execution inside of an application. At the system level, programs run side by side, with the system doling out execution time to each program based on its needs and the needs of other programs. Inside each program, however, exists one or more threads of execution, which can be used to perform different tasks simultaneously or in a nearly simultaneous manner. The system itself actually manages these threads of execution, scheduling them to run on the available cores and preemptively interrupting them as needed to allow other threads to run.

스레드 응용 프로그램 내에서 여러 실행 경로를 구현하는 비교적 간단한 방법입니다.시스템 레벨에서, 프로그램은 시스템이 요구 사항과 다른 프로그램의 필요에 따라 각 프로그램의 실행 시간을 해주기 때문에와 나란히 실행합니다. 각 프로그램 내에서, 그러나, 동시에 또는 거의 동시에 방법으로 다른 작업을 수행 할 수 있습니다 실행 스레드를 하나 이상 존재.시스템 자체는 실제로 사용 가능한 코어에서 실행하도록 예약하고 선제 적들을 다른 스레드를 실행할 수 있도록하는 데 필요한 중단, 실행이 스레드를 관리합니다.

From a technical standpoint, a thread is a combination of the kernel-level and application-level data structures needed to manage the execution of code. The kernel-level structures coordinate the dispatching of events to the thread and the preemptive scheduling of the thread on one of the available cores. The application-level structures include the call stack for storing function calls and the structures the application needs to manage and manipulate the thread’s attributes and state.

기술적 인 관점에서, 스레드는 커널 수준의 코드의 실행을 관리하는 데 필요한 응용 프로그램 수준 데이터 구조의 조합입니다.커널 레벨의 구조는 사용 가능한 코어 중 하나의 스레드와 스레드의 선점 스케줄링 이벤트 디스패치를 조정. 응용 프로그램 수준의 구조는 저장 함수를 호출하고 응용 프로그램 스레드의 특성과 상태를 관리하고 조작하는 데 필요한 구조에 대한 호출 스택 (가) 있습니다.

In a non-concurrent application, there is only one thread of execution. That thread starts and ends with your application’s main routine and branches one-by-one to different methods or functions to implement the application’s overall behavior. By contrast, an application that supports concurrency starts with one thread and adds more as needed to create additional execution paths. Each new path has its own custom start routine that runs independently of the code in the application’smain routine. Having multiple threads in an application provides two very important potential advantages:

비 동시 응용 프로그램에서 실행 한 스레드가있다. 해당 스레드는 응용 프로그램의 주 루틴 가지 다른 방법이나 응용 프로그램의 전반적인 동작을 구현하는 기능을 하나씩 시작하고 끝납니다. 대조적으로, 동시성을 지원하는 응용 프로그램은 하나의 스레드로 시작하고 추가 실행 경로를 생성하는 데 필요한 더 추가합니다. 각각의 새 경로는 독립적으로 application'smain 루틴에서 코드를 실행하는 자신의 사용자 정의 시작 루틴을 가지고 있습니다.응용 프로그램에서 여러 스레드를 갖는 것은 매우 중요한 두 가지 잠재적 인 이점을 제공합니다 :

  • Multiple threads can improve an application’s perceived responsiveness.
    다중 스레드 응용 프로그램의인지 응답을 개선 할 수 있습니다.

  • Multiple threads can improve an application’s real-time performance on multicore systems.
    여러 스레드가 멀티 코어 시스템에서 응용 프로그램의 실시간 성능을 향상시킬 수 있습니다.

If your application has only one thread, that one thread must do everything. It must respond to events, update your application’s windows, and perform all of the computations needed to implement your application’s behavior. The problem with having just one thread is that it can only do one thing at a time. So what happens when one of your computations takes a long time to finish? While your code is busy computing the values it needs, your application stops responding to user events and updating its windows. If this behavior continues long enough, a user might think your application is hung and try to forcibly quit it. If you moved your custom computations onto a separate thread, however, your application’s main thread would be free to respond to user interactions in a more timely manner.

응용 프로그램은 하나의 스레드가있는 경우, 그 하나의 쓰레드가 모든 작업을 수행해야합니다. 이것은 이벤트에 응답 응용 프로그램의 윈도우를 업데이트하고 응용 프로그램의 동작을 구현하는 데 필요한 계산을 모두 수행해야합니다. 단지 하나의 스레드를 갖는 문제는 한 번에 하나의 일을 할 수 있다는 것입니다. 귀하의 계산 중 하나 완료하는 데 오랜 시간이 걸리는 경우 그래서 어떻게됩니까? 코드는 필요한 값 바쁜 컴퓨팅이지만, 응용 프로그램은 사용자 이벤트에 응답하고 윈도우를 업데이트하지 않습니다. 이 문제가 오랫동안 계속되면, 사용자는 응용 프로그램이 걸려 생각하고 강제로 종료하려고 할 수도 있습니다. 당신이 별도의 스레드에 사용자 정의 계산을 이동 한 경우, 그러나, 응용 프로그램의 주 스레드는 더 적시에 사용자 상호 작용에 응답하여 주시기 될 것입니다.

With multicore computers common these days, threads provide a way to increase performance in some types of applications. Threads that perform different tasks can do so simultaneously on different processor cores, making it possible for an application to increase the amount of work it does in a given amount of time.

요즘 일반적인 컴퓨터를 멀티 코어 스레드는 일부 유형의 응용 프로그램 성능을 향상하는 방법을 제공합니다. 다른 작업을 수행하는 쓰레드는 가능한 응용 프로그램이 지정된 시간에가하는 일의 양을 증가하기 위해 만드는 다른 프로세서 코어에 이렇게 동시에 수행 할 수 있습니다.

Of course, threads are not a panacea for fixing an application’s performance problems. Along with the benefits offered by threads come the potential problems. Having multiple paths of execution in an application can add a considerable amount of complexity to your code. Each thread has to coordinate its actions with other threads to prevent it from corrupting the application’s state information. Because threads in a single application share the same memory space, they have access to all of the same data structures. If two threads try to manipulate the same data structure at the same time, one thread might overwrite another’s changes in a way that corrupts the resulting data structure. Even with proper protections in place, you still have to watch out for compiler optimizations that introduce subtle (and not so subtle) bugs into your code.

물론, 스레드 애플리케이션의 성능 문제를 해결하기위한 만병 통치약이 아닙니다. 함께 스레드에 의해 제공되는 혜택은 잠재적 인 문제를 온다.응용 프로그램의 여러 실행 경로를 갖는 코드의 복잡성 상당한 양의를 추가 할 수 있습니다. 각 스레드는 응용 프로그램의 상태 정보를 손상시키지 않도록하기 위해 다른 스레드의 작업을 조정합니다.하나의 응용 프로그램의 스레드가 같은 메모리 공간을 공유하기 때문에, 그들은 동일한 데이터 구조의 모든에 액세스 할 수 있습니다. 두 스레드가 동시에 같은 데이터 구조를 조작하려고하면, 하나의 스레드는 결과 데이터 구조가 손상 방법으로 다른 사람의 변경 내용을 덮어 쓸 수 있습니다. 심지어 장소에 적절한 보호와 함께, 당신은 여전히 귀하의 코드에 미묘 (그래서 미묘한) 버그를 소개 컴파일러 최적화를 조심해야합니다.

Threading Terminology
스레딩 용어

Before getting too far into discussions about threads and their supporting technologies, it is necessary to define some basic terminology.
스레드과 지원 기술에 대한 논의에 너무 멀리 얻기 전에, 몇 가지 기본 용어를 정의 할 필요가있다.

If you are familiar with UNIX systems, you may find that the term “task” is used differently by this document. On UNIX systems, the term “task” is used at times to refer to a running process.
당신은 UNIX 시스템에 익숙하다면, 당신은 용어 "작업"이 문서에서 다르게 사용되는 것을 알 수 있습니다. UNIX 시스템에서, 용어 "작업"실행중인 프로세스를 참조하는 시간에 사용됩니다.

This document adopts the following terminology:
이 문서에서는 다음 용어를 채택한다 :

  • The term thread is used to refer to a separate path of execution for code.
    용어는 스레드가 코드 별도의 실행 경로를 참조하는 데 사용됩니다.

  • The term process is used to refer to a running executable, which can encompass multiple threads.
    장기 과정은 여러 스레드를 포함 할 수있는 실행 실행을 참조하는 데 사용됩니다.

  • The term task is used to refer to the abstract concept of work that needs to be performed.
    용어 작업을 수행해야하는 작업의 추상적 인 개념을 참조하는 데 사용됩니다.

Alternatives to Threads
스레드에 대한 대안

One problem with creating threads yourself is that they add uncertainty to your code. Threads are a relatively low-level and complicated way to support concurrency in your application. If you do not fully understand the implications of your design choices, you could easily encounter synchronization or timing issues, the severity of which can range from subtle behavioral changes to the crashing of your application and the corruption of the user’s data.

스레드를 직접 만드는 하나의 문제는 그들이 코드에 불확실성을 추가하는 것입니다. 스레드 응용 프로그램에서 동시성을 지원하기 위해 상대적으로 낮은 수준의 복잡한 방법입니다. 당신이 완전히 디자인 선택의 의미를 이해하지 않는 경우에, 당신은 쉽게 동기화 또는 타이밍 문제, 미묘한 행동 변화에서 응용 프로그램과 사용자 데이터의 손상의 충돌에 이르기까지 다양 수의 심각도가 발생할 수 있습니다.

Another factor to consider is whether you need threads or concurrency at all. Threads solve the specific problem of how to execute multiple code paths concurrently inside the same process. There may be cases, though, where the amount of work you are doing does not warrant concurrency. Threads introduce a tremendous amount of overhead to your process, both in terms of memory consumption and CPU time. You may discover that this overhead is too great for the intended task, or that other options are easier to implement.

고려해야 할 또 다른 요소는 전혀 스레드 또는 동시성을 필요 여부입니다. 스레드가 동시에 동일한 프로세스 내에서 여러 개의 코드 경로를 실행하는 방법에 대한 특정 문제를 해결한다. 당신이하고있는 일의 양이 동시성을 보증하지 않습니다 어디 그러나, 경우가있을 수 있습니다. 스레드는 메모리 사용량과 CPU 시간의 측면에서, 프로세스에 오버 헤드 엄청난 양을 소개합니다. 이 오버 헤드는 다른 옵션을 구현하기 쉽게 원하는 작업, 또는 너무 큰 것을 발견 할 수 있습니다.

Table 1-1 lists some of the alternatives to threads. This table includes both replacement technologies for threads (such as operation objects and GCD) and alternatives that are geared towards efficiently using the single thread you already have.

표 1-1에게 스레드 대안의 일부를. 이 테이블은 스레드 (예 : 작업 개체와 GCD)와 효율적으로 당신은 이미 하나의 스레드를 사용하여 방향이 준비되어 있습니다 대안에 대한 대체 기술이 모두 포함됩니다.

Table 1-1  Alternative technologies to threads

Technology

Description

Operation objects

Introduced in OS X v10.5, an operation object is a wrapper for a task that would normally be executed on a secondary thread. This wrapper hides the thread management aspects of performing the task, leaving you free to focus on the task itself. You typically use these objects in conjunction with an operation queue object, which actually manages the execution of the operation objects on one or more threads.

OS X 10.5에 도입, 작업 개체는 일반적으로 보조 스레드에서 실행 될 작업에 대한 래퍼입니다. 이 래퍼는 작업 자체에만 집중할 수, 작업을 수행하는 스레드 관리 측면을 숨 깁니다. 당신은 일반적으로 실제로는 하나 이상의 스레드에서 작업 객체의 실행을 관리하는 작업 큐 개체와 함께 이러한 개체를 사용합니다.

For more information on how to use operation objects, see Concurrency Programming Guide.
작업 개체를 사용하는 방법에 대한 자세한 내용은 동시성 프로그래밍 가이드를 참조하십시오.

Grand Central Dispatch (GCD)

Introduced in Mac OS x v10.6, Grand Central Dispatch is another alternative to threads that lets you focus on the tasks you need to perform rather than on thread management. With GCD, you define the task you want to perform and add it to a work queue, which handles the scheduling of your task on an appropriate thread. Work queues take into account the number of available cores and the current load to execute your tasks more efficiently than you could do yourself using threads.

맥 OS X v10.6의에 도입, 그랜드 센트럴 디스패치를 사용하면 스레드 관리를 수행하는 대신해야하는 작업에 집중할 수 있도록 스레드에 대한 또 다른 대안입니다. GCD와 함께, 당신은 당신이 수행하고 해당 스레드에 작업의 스케줄링을 처리하는 작업 큐에 추가 할 작업을 정의합니다. 작업 큐 계정에 사용 가능한 코어의 수와 자신이 스레드를 사용 할 수있는 것보다 더 효율적으로 작업을 실행하는 현재의 부하를 가지고.

For information on how to use GCD and work queues, see Concurrency Programming Guide

GCD와 작업 큐를 사용하는 방법에 대한 자세한 내용은 동시성 프로그래밍 가이드를 참조하십시오

Idle-time notifications

For tasks that are relatively short and very low priority, idle time notifications let you perform the task at a time when your application is not as busy. Cocoa provides support for idle-time notifications using the NSNotificationQueue object. To request an idle-time notification, post a notification to the default NSNotificationQueue object using the NSPostWhenIdle option. The queue delays the delivery of your notification object until the run loop becomes idle. For more information, see Notification Programming Topics.

상대적으로 짧은 매우 낮은 우선 순위 작업의 유휴 시간 알림 응용 프로그램으로 사용 중이 아닐 때 시간에 작업을 수행 할 수 있습니다. 코코아 NSNotificationQueue 개체를 사용하여 유휴 시간 알림에 대한 지원을 제공합니다.유휴 시간 알림을 요청하려면 NSPostWhenIdle 옵션을 사용하여 기본 NSNotificationQueue 개체에 대한 알림을 게시 할 수 있습니다.런 루프가 유휴 상태가 될 때까지 대기열 알림 객체의 전달을 지연. 자세한 내용은 Notification 프로그래밍 항목을 참조하십시오.

Asynchronous functions

The system interfaces include many asynchronous functions that provide automatic concurrency for you. These APIs may use system daemons and processes or create custom threads to perform their task and return the results to you. (The actual implementation is irrelevant because it is separated from your code.) As you design your application, look for functions that offer asynchronous behavior and consider using them instead of using the equivalent synchronous function on a custom thread.

시스템 인터페이스는 당신을 위해 자동으로 동시성을 제공하는 많은 비동기 기능이 있습니다. 이 API는 시스템 데몬 및 프로세스를 사용하거나 자신의 작업을 수행하고 당신에게 결과를 반환하는 사용자 지정 스레드를 만들 수 있습니다. (그것은 당신의 코드에서 분리되어 있기 때문에 실제 구현은 무관하다.) 응용 프로그램을 설계 할 때, 비동기 동작을 제공하고이를 사용하는 대신 사용자 지정 스레드에서 해당 동기 기능을 사용하는 것이 함수를 찾습니다.

Timers

You can use timers on your application’s main thread to perform periodic tasks that are too trivial to require a thread, but which still require servicing at regular intervals. For information on timers, see “Timer Sources.”

당신은 스레드를 필요로하기에 너무 사소한,하지만 여전히 정기적으로 서비스 요구하는 정기적 인 작업을 수행하는 응용 프로그램의 주 스레드에서 타이머를 사용할 수 있습니다. 타이머에 대한 자세한 내용은 "타이머 소스"를 참조하십시오.

Separate processes

Although more heavyweight than threads, creating a separate process might be useful in cases where the task is only tangentially related to your application. You might use a process if a task requires a significant amount of memory or must be executed using root privileges. For example, you might use a 64-bit server process to compute a large data set while your 32-bit application displays the results to the user.

별도의 프로세스를 생성, 스레드보다 더 헤비급 작업 만 접선 응용 프로그램에 관련되는 경우에 유용 할 수 있지만. 작업이 상당한 양의 메모리를 필요로하거나 루트 권한을 사용하여 실행해야하는 경우는 프로세스를 사용할 수 있습니다. 예를 들어, 32 비트 응용 프로그램이 사용자에게 결과를 표시하면서 큰 데이터 집합을 계산하는 64 비트 서버 프로세스를 사용할 수 있습니다.

Threading Support
지원 스레딩

If you have existing code that uses threads, OS X and iOS provide several technologies for creating threads in your applications. In addition, both systems also provide support for managing and synchronizing the work that needs to be done on those threads. The following sections describe some of the key technologies that you need to be aware of when working with threads in OS X and iOS.

스레드를 사용하는 코드를 기존의 경우, OS X 및 IOS는 응용 프로그램에서 스레드를 생성하기위한 여러 가지 기술을 제공합니다. 또한 두 시스템은 해당 스레드에서 수행해야 할 작업을 관리하고 동기화에 대한 지원을 제공합니다.다음 섹션에서는 OS X 및 IOS의 스레드로 작업 할 때 알아 두어야 할 핵심 기술 중 일부를 설명합니다.

Threading Packages

스레딩 패키지

Although the underlying implementation mechanism for threads is Mach threads, you rarely (if ever) work with threads at the Mach level. Instead, you usually use the more convenient POSIX API or one of its derivatives. The Mach implementation does provide the basic features of all threads, however, including the preemptive execution model and the ability to schedule threads so they are independent of each other.

마하 수준에서 스레드와 스레드에 대한 기본 구현 메커니즘은 마하 스레드이지만, 당신은 거의 (면 적) 작동합니다. 대신, 당신은 일반적으로 더 편리 POSIX API 또는 그 유도체 중 하나를 사용하십시오.마하 구현은 선제 적 실행 모델들은 서로 독립적이되도록 스레드를 예약 할 수있는 능력을 포함한 모든 스레드의 기본 기능을하지만, 제공한다.

Listing 2-2 lists the threading technologies you can use in your applications.
목록 2-2는 응용 프로그램에서 사용할 수있는 스레딩 기술을 보여줍니다.

Table 1-2  Thread technologies

Technology

Description

Cocoa threads

Cocoa implements threads using the NSThread class. Cocoa also provides methods on NSObject for spawning new threads and executing code on already-running threads. For more information, see “Using NSThread” and “Using NSObject to Spawn a Thread.”

코코아 NSThread 클래스를 사용하여 스레드를 구현합니다. 코코아는 산란 새 스레드 NSObject의에 대한 방법과 이미 실행중인 스레드에서 실행되는 코드를 제공합니다. 자세한 내용은 "NSThread 사용"을 참조하십시오 "스레드를 생성하는 NSObject의 사용"을 참조하십시오.

POSIX threads

POSIX threads provide a C-based interface for creating threads. If you are not writing a Cocoa application, this is the best choice for creating threads. The POSIX interface is relatively simple to use and offers ample flexibility for configuring your threads. For more information, see“Using POSIX Threads”

POSIX 스레드는 스레드를 생성하기위한 C 기반의 인터페이스를 제공합니다. 당신은 코코아 응용 프로그램을 작성하지 않은 경우,이 스레드를 만들기위한 최고의 선택입니다.POSIX 인터페이스를 사용하는 비교적 간단하고 스레드를 구성하기위한 충분한 유연성을 제공합니다. 자세한 내용은 "POSIX 스레드 사용"을 참조하십시오

Multiprocessing Services

Multiprocessing Services is a legacy C-based interface used by applications transitioning from older versions of Mac OS. This technology is available in OS X only and should be avoided for any new development. Instead, you should use the NSThread class or POSIX threads. If you need more information on this technology, see Multiprocessing Services Programming Guide.

멀티 서비스는 Mac OS의 이전 버전에서 전환 응용 프로그램에서 사용하는 기존 C 기반의 인터페이스입니다. 이 기술은 OS X에서 사용할 수 있으며 새로운 발전을 위해 피해야한다. 대신에, 당신은 NSThread 클래스 또는 POSIX 스레드를 사용합니다. 이 기술에 대한 자세한 정보가 필요하면 멀티 프로세싱 서비스 프로그래밍 가이드를 참조하십시오.

At the application level, all threads behave in essentially the same way as on other platforms. After starting a thread, the thread runs in one of three main states: running, ready, or blocked. If a thread is not currently running, it is either blocked and waiting for input or it is ready to run but not scheduled to do so yet. The thread continues moving back and forth among these states until it finally exits and moves to the terminated state.

응용 프로그램 수준에서 모든 스레드는 다른 플랫폼에 본질적으로 동일한 방식으로 작동합니다. 준비, 또는 차단 실행 : 스레드를 시작하면 스레드는 세 가지 상태 중 하나에서 실행됩니다.스레드가 현재 실행되고 있지 않은 경우, 어느 차단하고 입력을 대기하거나 실행할 준비가 아직 그렇게 예정되어 있지 않습니다.스레드가 이러한 상태 사이를 앞뒤로 이동 계속 그것을 마지막으로 종료하고 종료 상태로 이동할 때까지.

When you create a new thread, you must specify an entry-point function (or an entry-point method in the case of Cocoa threads) for that thread. This entry-point function constitutes the code you want to run on the thread. When the function returns, or when you terminate the thread explicitly, the thread stops permanently and is reclaimed by the system. Because threads are relatively expensive to create in terms of memory and time, it is therefore recommended that your entry point function do a significant amount of work or set up a run loop to allow for recurring work to be performed.

당신은 새 스레드를 만들 때 해당 스레드에 대한 진입 점 함수 (또는 코코아 스레드의 경우 진입 점 방식)를 지정해야합니다. 이 엔트리 포인트 함수는 스레드에서 실행하고자하는 코드를 구성합니다.함수가 반환 할 때 또는 당신이 명시 적으로 스레드를 종료하면 스레드는 영구적으로 중지하고 시스템에 의해 회수된다. 스레드가 메모리와 시간의 관점에서 작성 상대적으로 고가이기 때문에, 따라서 귀하의 진입 점 함수가 상당한 양의 작업을 수행하거나 실행 루프를 수행 할 반복 작업이 가능하도록을 설정하는 것이 좋습니다.

For more information about the available threading technologies and how to use them, see “Thread Management.”

사용 가능한 스레딩 기술을 사용하는 방법에 대한 자세한 내용은 "스레드 관리"를 참조하십시오.

Run Loops

루프를 실행

A run loop is a piece of infrastructure used to manage events arriving asynchronously on a thread. A run loop works by monitoring one or more event sources for the thread. As events arrive, the system wakes up the thread and dispatches the events to the run loop, which then dispatches them to the handlers you specify. If no events are present and ready to be handled, the run loop puts the thread to sleep.

런 루프는 스레드에서 비동기 적으로 도착하는 이벤트를 관리하는 데 사용되는 인프라의 조각이다.런 루프는 스레드에 대해 하나 이상의 이벤트 소스를 모니터링하는 방식으로 작동합니다. 이벤트가 도착하면, 시스템은 스레드 실행 루프 전달 이벤트를 깨어 그 어느 지정 처리기 디스패치합니다. 어떤 이벤트가 존재하고 처리 할 준비가되지 않으면, 실행 루프는 잠을 스레드를 넣습니다.

You are not required to use a run loop with any threads you create but doing so can provide a better experience for the user. Run loops make it possible to create long-lived threads that use a minimal amount of resources. Because a run loop puts its thread to sleep when there is nothing to do, it eliminates the need for polling, which wastes CPU cycles and prevents the processor itself from sleeping and saving power.

당신은 당신이 만드는 모든 스레드가 실행 루프를 사용할 필요는 없습니다 만, 이렇게하면 사용자에게 더 나은 경험을 제공 할 수 있습니다. 루프가 가능한 최소한의 자원을 사용하여 수명이 긴 스레드를 만들 수 있도록 실행합니다.실행 루프 아무 상관이 없을 때 수면의 스레드를두고 있기 때문에, CPU 사이클을 낭비 전원을 자고 저장에서 프로세서 자체를 방지 폴링에 대한 필요가 없습니다.

To configure a run loop, all you have to do is launch your thread, get a reference to the run loop object, install your event handlers, and tell the run loop to run. The infrastructure provided by OS X handles the configuration of the main thread’s run loop for you automatically. If you plan to create long-lived secondary threads, however, you must configure the run loop for those threads yourself.

런 루프를 구성하려면, 당신이해야 할 모든 당신의 스레드를 실행 실행 루프 개체에 대한 참조를 얻을 이벤트 처리기를 설치하고 실행하는 실행 루프를 알 수 있습니다. OS X에서 제공하는 인프라는 자동으로 메인 스레드의 실행 루프의 구성을 처리합니다. 당신이 오래 지속 보조 스레드를 생성하려는 경우, 그러나, 당신은 그 스레드 직접 실행 루프를 구성해야합니다.

Details about run loops and examples of how to use them are provided in “Run Loops.”
실행 루프를 사용하는 방법의 예제에 대한 자세한 내용은에서 제공하는 "실행 루프."

Synchronization Tools

동기화 도구

One of the hazards of threaded programming is resource contention among multiple threads. If multiple threads try to use or modify the same resource at the same time, problems can occur. One way to alleviate the problem is to eliminate the shared resource altogether and make sure each thread has its own distinct set of resources on which to operate. When maintaining completely separate resources is not an option though, you may have to synchronize access to the resource using locks, conditions, atomic operations, and other techniques.

스레드 프로그래밍의 위험 중 하나는 여러 스레드간에 리소스 경합입니다. 여러 스레드가 동시에 같은 리소스를 사용하거나 수정하려고하면 문제가 발생할 수 있습니다.문제를 완화하는 한 가지 방법은 모두 공유 리소스를 제거하고 각 스레드가 작동 할 수있는 자원의 독특한 설정을 가지고 있는지 확인하는 것입니다. 완전히 별개의 자원을 유지하는 것이 비록 옵션이없는 경우, 당신은 자물쇠, 조건, 원자 작업 및 기타 기술을 사용하여 리소스에 대한 액세스를 동기화 할 수 있습니다.

Locks provide a brute force form of protection for code that can be executed by only one thread at a time. The most common type of lock is mutual exclusion lock, also known as a mutex. When a thread tries to acquire a mutex that is currently held by another thread, it blocks until the lock is released by the other thread. Several system frameworks provide support for mutex locks, although they are all based on the same underlying technology. In addition, Cocoa provides several variants of the mutex lock to support different types of behavior, such as recursion. For more information about the available types of locks, see “Locks.”

잠금은 한 번에 하나의 스레드에 의해 실행될 수있는 코드에 대한 보호의 무력 양식을 제공합니다. 자물쇠의 가장 일반적인 유형은 뮤텍스로 알려진 상호 배제 잠금입니다.스레드는 현재 다른 thread에 의해 보관 유지되고있는 뮤텍스를 획득하려고 할 때, 잠금 때까지이 블록은 다른 스레드에 의해 해제됩니다. 그들은 모두 동일한 기본 기술을 기반으로하지만 여러 시스템 프레임 워크, 뮤텍스 잠금에 대한 지원을 제공합니다. 또한, 코코아는 재귀 같은 행동의 다른 유형을 지원하기 위해 뮤텍스 잠금의 여러 변종을 제공합니다. 잠금 장치의 사용 가능한 형식에 대한 자세한 내용은 "잠금"을 참조하십시오.

In addition to locks, the system provides support for conditions, which ensure the proper sequencing of tasks within your application. A condition acts as a gatekeeper, blocking a given thread until the condition it represents becomes true. When that happens, the condition releases the thread and allows it to continue. The POSIX layer and Foundation framework both provide direct support for conditions. (If you use operation objects, you can configure dependencies among your operation objects to sequence the execution of tasks, which is very similar to the behavior offered by conditions.)

잠금 외에도, 시스템은 응용 프로그램 내에서 작업의 적절한 시퀀싱을 보장하는 조건에 대한 지원을 제공합니다.조건이 나타내는 조건이 참이 될 때까지 해당 스레드를 차단, 게이트 키퍼 역할을합니다. 그렇게되면, 상태는 스레드를 해제하고 ​​계속할 수 있습니다.POSIX 레이어 및 기초 프레임 워크 조건에 대한 직접적인 지원을 제공 둘. (당신은 작업 개체를 사용하는 경우, 당신은 순서에 작업 개체간에 조건에 의해 제공되는 동작과 매우 유사 작업의 실행을 종속성을 구성 할 수 있습니다.)

Although locks and conditions are very common in concurrent design, atomic operations are another way to protect and synchronize access to data. Atomic operations offer a lightweight alternative to locks in situations where you can perform mathematical or logical operations on scalar data types. Atomic operations use special hardware instructions to ensure that modifications to a variable are completed before other threads have a chance to access it.

잠금 및 조건이 동시 설계에서 매우 일반적이지만, 원자 작업은 데이터에 대한 액세스를 보호하고 동기화하는 또 다른 방법입니다. 원자 연산은 스칼라 데이터 형식에 대한 수학적 또는 논리적 연산을 수행 할 수있는 상황에서 잠금에 경량 대안을 제공합니다. 원자 작업이 다른 스레드가 액세스 할 수있는 기회를 갖기도 전에 변수에 대한 수정이 완료되는 것을 보장하기 위해 특별한 하드웨어 명령을 사용합니다.

For more information about the available synchronization tools, see “Synchronization Tools.”
사용 가능한 동기화 도구에 대한 자세한 내용은 "동기화 도구"를 참조하십시오.

Inter-thread Communication

스레드 간 통신

Although a good design minimizes the amount of required communication, at some point, communication between threads becomes necessary. (A thread’s job is to do work for your application, but if the results of that job are never used, what good is it?) Threads may need to process new job requests or report their progress to your application’s main thread. In these situations, you need a way to get information from one thread to another. Fortunately, the fact that threads share the same process space means you have lots of options for communication.

좋은 디자인은 어떤 시점에서, 필요한 통신의 양을 최소화하지만, 스레드 간의 통신이 필요하게됩니다. (스레드의 작업이 응용 프로그램에 대한 작업을 수행하는 것입니다,하지만 그 작업의 결과를 사용하지 않을 경우, 좋은 무엇입니까?) 스레드는 새 작업 요청을 처리하거나 응용 프로그램의 주 스레드에 진행 상황을보고해야 할 수도 있습니다. 이러한 상황에서는, 당신은 하나의 스레드에서 다른 정보를 얻을 수있는 방법이 필요합니다. 다행히도, 스레드가 동일한 프로세스 공간을 공유한다는 사실은 통신을위한 많은 옵션을 의미합니다.

There are many ways to communicate between threads, each with its own advantages and disadvantages. “Configuring Thread-Local Storage” lists the most common communication mechanisms you can use in OS X. (With the exception of message queues and Cocoa distributed objects, these technologies are also available in iOS.) The techniques in this table are listed in order of increasing complexity.

스레드간에 통신하는 방법에는 여러 가지, 자신의 장점과 단점이 각각 있습니다. "스레드 로컬 저장소를 구성하는 것은"당신이 OS X에서 사용할 수있는 가장 일반적인 통신 메커니즘을 나열합니다 (메시지 큐와 코코아 분산 객체를 제외하고, 이러한 기술은 또한 IOS에서 사용할 수 있습니다.)이 테이블의 기술을 순서대로 나열되어 있습니다 복잡성이 증가.

Table 1-3  Communication mechanisms

Mechanism

Description

Direct messaging

Cocoa applications support the ability to perform selectors directly on other threads. This capability means that one thread can essentially execute a method on any other thread. Because they are executed in the context of the target thread, messages sent this way are automatically serialized on that thread. For information about input sources, see “Cocoa Perform Selector Sources.”

코코아 응용 프로그램에서 직접 다른 스레드에서 선택기를 수행 할 수있는 기능을 지원합니다. 이 기능은 하나의 스레드는 기본적으로 다른 스레드에서 메서드를 실행할 수 있다는 것을 의미합니다. 그들이 대상 스레드의 컨텍스트에서 실행되기 때문에 메시지는이 방법이 자동으로 해당 스레드에 직렬화되어 전송됩니다. 입력 소스에 대한 자세한 내용은 "코코아 선택기 소스를 수행"을 참조하십시오.

Global variables, shared memory, and objects

Another simple way to communicate information between two threads is to use a global variable, shared object, or shared block of memory. Although shared variables are fast and simple, they are also more fragile than direct messaging. Shared variables must be carefully protected with locks or other synchronization mechanisms to ensure the correctness of your code. Failure to do so could lead to race conditions, corrupted data, or crashes.

두 개의 스레드 사이에서 정보를 전달하는 또 다른 간단한 방법은 전역 변수, 공유 객체, 또는 메모리의 공유 블록을 사용하는 것입니다. 공유 변수는 빠르고 간단하지만, 그들은 또한 직접 메시지보다 더 허약하다. 공유 변수는주의 깊게 코드의 정확성을 보장하기 위해 잠금이나 다른 동기화 메커니즘으로 보호해야합니다. 그렇지 않으면 경쟁 조건, 데이터 손상 또는 충돌로 이어질 수 있습니다.

Conditions

Conditions are a synchronization tool that you can use to control when a thread executes a particular portion of code. You can think of conditions as gate keepers, letting a thread run only when the stated condition is met. For information on how to use conditions, see “Using Conditions.”

상태는 스레드가 코드의 특정 부분을 실행할 때 제어하는 데 사용할 수있는 동기화 도구입니다. 당신은 명시된 조건이 충족되는 경우에만 스레드를 실행시키는 문 계원으로 조건을 생각할 수 있습니다. 조건을 사용하는 방법에 대한 자세한 내용은 "조건 사용"을 참조하십시오.

Run loop sources

A custom run loop source is one that you set up to receive application-specific messages on a thread. Because they are event driven, run loop sources put your thread to sleep automatically when there is nothing to do, which improves your thread’s efficiency. For information about run loops and run loop sources, see “Run Loops.”

사용자 정의 실행 루프 소스는 스레드에서 응용 프로그램 특정 메시지를 수신하도록 설정하는 하나입니다. 그들은 이벤트 구동 때문에, 루프 소스가 스레드의 효율성을 향상 할 수있는 것도이 없을 때 자동으로 잠자기 상태로 스레드를 넣어 실행합니다. 실행 루프에 대한 정보와 실행 루프 소스의 경우, "실행 루프"를 참조하십시오.

Ports and sockets

Port-based communication is a more elaborate way to communication between two threads, but it is also a very reliable technique. More importantly, ports and sockets can be used to communicate with external entities, such as other processes and services. For efficiency, ports are implemented using run loop sources, so your thread sleeps when there is no data waiting on the port. For information about run loops and about port-based input sources, see “Run Loops.”

포트 기반 통신은 두 개의 스레드 사이의 통신에 대한보다 정교한 방법이지만, 그것은 또한 매우 신뢰할 수있는 기술입니다. 더 중요한 것은, 포트 및 소켓과 같은 다른 프로세스와 서비스와 같은 외부 개체와 통신하는 데 사용할 수 있습니다. 효율성을 위해 포트가 실행 루프 소스를 사용하여 구현됩니다, 포트에서 대기중인 데이터가없는 때 스레드가 잠들 때문에. 실행 루프에 대한 및 포트 기반의 입력 소스에 대한 자세한 내용은 "실행 루프"를 참조하십시오.

Message queues

The legacy Multiprocessing Services defines a first-in, first-out (FIFO) queue abstraction for managing incoming and outgoing data. Although message queues are simple and convenient, they are not as efficient as some other communications techniques. For more information about how to use message queues, see Multiprocessing Services Programming Guide.

기존의 다중 서비스 수신 및 발신 데이터를 관리하기위한 선입 선출 (FIFO) 큐 추상화를 정의합니다. 메시지 큐가 간단하고 편리하지만, 그들은 다른 통신 기술로 효율적으로하지 않습니다. 메시지 큐를 사용하는 방법에 대한 자세한 내용은 다중 서비스 프로그래밍 가이드를 참조하십시오.

Cocoa distributed objects

Distributed objects is a Cocoa technology that provides a high-level implementation of port-based communications. Although it is possible to use this technology for inter-thread communication, doing so is highly discouraged because of the amount of overhead it incurs. Distributed objects is much more suitable for communicating with other processes, where the overhead of going between processes is already high. For more information, see Distributed Objects Programming Topics.

istributed 개체는 포트 기반 통신에 대한 높은 수준의 구현을 제공하는 코코아 기술입니다. 이 스레드 간 통신을 위해이 기술을 사용할 수 있지만, 이렇게하면 높은 오버 헤드 때문에 그것은 풋의 양 좋습니다. 분산 객체는 프로세스 사이가는 오버 헤드가 이미 높은 다른 프로세스와의 통신에 훨씬 더 적합합니다. 자세한 내용은 분산 객체 프로그래밍 항목을 참조하십시오.

Design Tips
디자인 팁

The following sections offer guidelines to help you implement threads in a way that ensures the correctness of your code. Some of these guidelines also offer tips for achieving better performance with your own threaded code. As with any performance tips, you should always gather relevant performance statistics before, during, and after you make changes to your code.

다음 섹션에서는 코드의 정확성을 보장하는 방식으로 스레드를 구현하는 데 도움이되는 가이드 라인을 제공합니다. 이러한 지침 중 일부는 자신의 스레드 코드와 더 나은 성능을 달성하기위한 팁을 제공합니다. 모든 성능 정보와 마찬가지로, 당신은 항상 동안, 전에 관련 성능 통계를 수집해야합니다, 당신은 당신의 코드를 변경 한 후.

Avoid Creating Threads Explicitly

명시 적으로 스레드를 생성하지 않도록

Writing thread-creation code manually is tedious and potentially error-prone and you should avoid it whenever possible. OS X and iOS provide implicit support for concurrency through other APIs. Rather than create a thread yourself, consider using asynchronous APIs, GCD, or operation objects to do the work. These technologies do the thread-related work behind the scenes for you and are guaranteed to do it correctly. In addition, technologies such as GCD and operation objects are designed to manage threads much more efficiently than your own code ever could by adjusting the number of active threads based on the current system load. For more information about GCD and operation objects, see Concurrency Programming Guide.

스레드 생성 코드를 작성 수동으로 지루한 잠재적 오류 발생 가능성이 커지므로 가능하면 당신은 그것을 피해야한다. OS X 및 IOS는 다른 API를 통해 동시성에 대한 암시 적 지원을 제공합니다.스레드를 직접 생성하는 대신, 작업을 수행하는 비동기 API를, GCD, 또는 조작 객체를 사용하는 것이 좋습니다. 이 기술은 당신을 위해 내부적으로 스레드 관련 작업을 수행하고 올바르게 수행 할 보장됩니다. 또, GCD 및 운영 객체와 같은 기술은 현재 시스템로드에 따라 활성 스레드의 수를 조정하여 훨씬 더 효율적으로 자신의 코드 어느 때보 수 스레드를 관리 할 수 ​​있도록 설계되어 있습니다. GCD 및 작업 개체에 대한 자세한 내용은 동시성 프로그래밍 가이드를 참조하십시오.

Keep Your Threads Reasonably Busy

귀하의 스레드가 합리적으로 바쁘게

If you decide to create and manage threads manually, remember that threads consume precious system resources. You should do your best to make sure that any tasks you assign to threads are reasonably long-lived and productive. At the same time, you should not be afraid to terminate threads that are spending most of their time idle. Threads use a nontrivial amount of memory, some of it wired, so releasing an idle thread not only helps reduce your application’s memory footprint, it also frees up more physical memory for other system processes to use.

만들고 수동으로 스레드를 관리하기로 결정한 경우, 스레드가 귀중한 시스템 리소스를 소비하는 기억. 당신은 당신이 스레드에 할당하는 작업을 합리적으로 긴 수명 및 생산성 있는지 확인하기 위해 최선을 다해야 할 것입니다. 동시에, 당신은 유휴 대부분의 시간을 소비하는 스레드를 종료하는 것을 두려워해서는 안됩니다. 스레드가 메모리 사소하지 않은 금액을 사용, 그것의 일부가되도록 응용 프로그램의 메모리 사용량을 줄이는 데 도움이뿐만 아니라 유휴 스레드를 해제, 유선, 또한 다른 시스템 프로세스가 사용하는 물리적 메모리를 해제합니다.

Avoid Shared Data Structures

공유 데이터 구조를 방지

The simplest and easiest way to avoid thread-related resource conflicts is to give each thread in your program its own copy of whatever data it needs. Parallel code works best when you minimize the communication and resource contention among your threads.

스레드 관련 리소스 충돌을 방지하기 위해 간단하고 쉬운 방법은 프로그램에 필요한 어떤 데이터의 복사본을 각 스레드를 제공하는 것입니다. 당신이 스레드간에 통신 및 리소스 경합을 최소화 할 때 병렬 코드를 가장 잘 작동합니다.

Creating a multithreaded application is hard. Even if you are very careful and lock shared data structures at all the right junctures in your code, your code may still be semantically unsafe. For example, your code could run into problems if it expected shared data structures to be modified in a specific order. Changing your code to a transaction-based model to compensate could subsequently negate the performance advantage of having multiple threads. Eliminating the resource contention in the first place often results in a simpler design with excellent performance.

다중 스레드 응용 프로그램을 작성하는 것은 어렵습니다. 당신은 코드의 모든 권리 고비 매우 신중하고 잠금 공유 데이터 구조 인 경우에도, 귀하의 코드는 여전히 의미가 안전하지 않을 수 있습니다. 이 특정 순서로 수정할 수있는 공유 데이터 구조를 예상하는 경우 예를 들어, 코드는 문제에 실행할 수 있습니다. 보상하는 트랜잭션 기반 모델에 코드를 변경하면 이후 여러 스레드를 갖는 성능상의 이점을 무효화 할 수 있습니다. 처음에 자원 경합을 제거하면 종종 우수한 성능을 가진 단순한 설계 결과.

Threads and Your User Interface

스레드와 사용자 인터페이스

If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your application’s main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface.

응용 프로그램이 그래픽 사용자 인터페이스를 가지고 있다면, 그것은 당신이 사용자 관련 이벤트를 수신하고 응용 프로그램의 주 스레드에서 인터페이스 업데이트를 시작하는 것이 좋습니다. 이 방법은 사용자 이벤트를 처리하고 윈도우 내용을 도면과 관련된 동기화 문제를 방지하는 데 도움이됩니다. 같은 코코아와 같은 일부 프레임 워크, 일반적으로이 동작을 필요로하지만, 심지어는 주 스레드에서이 동작을 유지하지 않는 사람들을 위해 사용자 인터페이스를 관리하기위한 논리를 단순화의 이점이있다.

There are a few notable exceptions where it is advantageous to perform graphical operations from other threads. For example, you can use secondary threads to create and process images and perform other image-related calculations. Using secondary threads for these operations can greatly increase performance. If you are not sure about a particular graphical operation though, plan on doing it from your main thread.

그것은 다른 스레드에서 그래픽 작업을 수행 할 유리한 몇 가지 주목할만한 예외가 있습니다. 예를 들어, 생성하고 처리하는 이미지 및 기타 이미지 관련 계산을 수행 할 보조 스레드를 사용할 수 있습니다. 이러한 작업을 위해 보조 스레드를 사용하여 성능을 크게 향상시킬 수 있습니다. 당신은 당신의 주 스레드에서 수행하는 방법에 대한 계획,하지만 특정 그래픽 작업에 대한 확실하지 않은 경우.

For more information about Cocoa thread safety, see “Thread Safety Summary.” For more information about drawing in Cocoa, see Cocoa Drawing Guide.

코코아 스레드 안전에 대한 자세한 내용은 코코아 그리기에 대한 자세한 내용은 "스레드 안전 요약"을 참조하십시오., 코코아 드로잉 설명서를 참조하십시오.

Be Aware of Thread Behaviors at Quit Time

Quit (종료) 시간에 스레드 동작을 인식

A process runs until all non-detached threads have exited. By default, only the application’s main thread is created as non-detached, but you can create other threads that way as well. When the user quits an application, it is usually considered appropriate behavior to terminate all detached threads immediately, because the work done by detached threads is considered optional. If your application is using background threads to save data to disk or do other critical work, however, you may want to create those threads as non-detached to prevent the loss of data when the application exits.

모든 비 분리 된 스레드가 종료 될 때까지 프로세스가 실행됩니다. 기본적으로 응용 프로그램의 주 스레드가 아닌 분리로 만들어집니다,하지만 당신은뿐만 아니라 다른 스레드에게 그 방법을 만들 수 있습니다. 분리 된 스레드에 의해 수행 작업이 선택적으로 간주되기 때문에 사용자가 응용 프로그램을 종료 할 때 일반적으로, 즉시 모든 분리 된 스레드를 종료하는 적절한 행동으로 간주됩니다. 응용 프로그램이 다른 중요한 작업을 디스크에 데이터를 저장하거나 수행하는 백그라운드 스레드를 사용하는 경우, 그러나, 당신은 데이터 손실 응용 프로그램이 종료되지 않도록 비 분리로 해당 스레드를 만들 수 있습니다.

Creating threads as non-detached (also known as joinable) requires extra work on your part. Because most high-level thread technologies do not create joinable threads by default, you may have to use the POSIX API to create your thread. In addition, you must add code to your application’s main thread to join with the non-detached threads when they do finally exit. For information on creating joinable threads, see “Setting the Detached State of a Thread.”

(또한 조인이라고도 함) 비 분리로 작성 스레드 부분에 추가 작업이 필요합니다. 가장 높은 수준의 스레드 기술은 기본적으로 조인 스레드를 생성하지 않기 때문에, 당신은 당신의 스레드를 생성하는 POSIX API를 사용 할 수 있습니다. 또한, 당신은 그들이 마지막으로 종료 않는 경우가 아닌 분리 된 스레드를 결합하는 응용 프로그램의 주 스레드에 코드를 추가해야합니다. 결합 가능한 스레드를 만드는 방법에 대한 자세한 내용은 "스레드의 분리 상태 설정"을 참조하십시오.

If you are writing a Cocoa application, you can also use the applicationShouldTerminate: delegate method to delay the termination of the application until a later time or cancel it altogether. When delaying termination, your application would need to wait until any critical threads have finished their tasks and then invoke the replyToApplicationShouldTerminate: method. For more information on these methods, see NSApplication Class Reference.

당신은 코코아 응용 프로그램을 작성하는 경우, 당신은 또한 applicationShouldTerminate을 사용할 수 있습니다 : 대리자 메서드를 나중에까지 응용 프로그램의 종료를 지연 또는 전부를 취소 할 수 있습니다. 방법 : 종료를 지연하는 경우, 응용 프로그램은 중요한 스레드가 작업을 완료 한 후 replyToApplicationShouldTerminate를 호출 할 때까지 대기해야합니다. 이러한 메서드에 대한 자세한 내용은 NSApplication 클래스 참조를 참조하십시오.

Handle Exceptions

예외 처리

Exception handling mechanisms rely on the current call stack to perform any necessary clean up when an exception is thrown. Because each thread has its own call stack, each thread is therefore responsible for catching its own exceptions. Failing to catch an exception in a secondary thread is the same as failing to catch an exception in your main thread: the owning process is terminated. You cannot throw an uncaught exception to a different thread for processing.

예외 처리 메커니즘은 예외가 throw 될 때 모든 필요한 정리를 수행 할 현재 호출 스택에 의존하고 있습니다. 각 스레드가 자신의 호출 스택을 가지고 있기 때문에, 각 스레드는 자신의 예외를 잡는 따라서 책임이 있습니다.소유하는 프로세스가 종료됩니다 : 보조 스레드에서 예외를 catch하는 데 실패하면 기본 스레드에서 예외를 catch하지 못하는 것과 동일합니다. 당신은 처리를 위해 다른 스레드에 캐치되지 않는 예외를 throw 할 수 없습니다.

If you need to notify another thread (such as the main thread) of an exceptional situation in the current thread, you should catch the exception and simply send a message to the other thread indicating what happened. Depending on your model and what you are trying to do, the thread that caught the exception can then continue processing (if that is possible), wait for instructions, or simply exit.

현재 스레드에서 예외 상황을 다른 스레드 (예 : 주 스레드)를 통보해야하는 경우, 당신은 예외를 catch하고 단순히 무슨 일이 있었는지 나타내는 다른 스레드에 메시지를 보내야합니다. 모델과 실행하려고에 따라 예외를 잡은 쓰레드가 그 (즉, 가능한 경우) 처리를 계속할 수 있습니다 지침을 기다리거나 단순히 종료합니다.

In some cases, an exception handler may be created for you automatically. For example, the @synchronized directive in Objective-C contains an implicit exception handler.

어떤 경우에는, 예외 핸들러가 자동으로 생성 할 수 있습니다. 예를 들어, 오브젝티브-C에서 @ 동기화 지시어는 암시 적 예외 처리기가 포함되어 있습니다.

Terminate Your Threads Cleanly

깔끔하게 스레드 종료

The best way for a thread to exit is naturally, by letting it reach the end of its main entry point routine. Although there are functions to terminate threads immediately, those functions should be used only as a last resort. Terminating a thread before it has reached its natural end point prevents the thread from cleaning up after itself. If the thread has allocated memory, opened a file, or acquired other types of resources, your code may be unable to reclaim those resources, resulting in memory leaks or other potential problems.

종료 스레드 가장 좋은 방법은 그것의 주 진입 점 루틴의 끝에 도달시키는 것으로, 자연스럽게. 바로 스레드를 종료하는 기능이 있지만, 그 기능은 최후의 수단으로 만 사용해야합니다. 그것의 자연 종점 자체 후 청소에서 스레드를 방지 도달하기 전에 스레드 종료.스레드가 메모리를 할당 한 경우, 파일을 열거 나 다른 유형의 리소스를 인수 코드는 메모리 누수 또는 기타 잠재적 인 문제가 발생, 그 자원을 재생하지 못할 수 있습니다.

For more information on the proper way to exit a thread, see “Terminating a Thread.”
스레드를 종료하는 적절한 방법에 대한 자세한 내용은 "스레드 종료"를 참조하십시오.

Thread Safety in Libraries

라이브러리에서 스레드로부터의 안전성

Although an application developer has control over whether an application executes with multiple threads, library developers do not. When developing libraries, you must assume that the calling application is multithreaded or could switch to being multithreaded at any time. As a result, you should always use locks for critical sections of code.

응용 프로그램 개발자가 응용 프로그램이 여러 스레드 실행 여부를 제어 할 있지만, 라이브러리 개발자는하지 않습니다. 라이브러리를 개발할 때, 당신은 호출 응용 프로그램이 다중 스레드 언제든지 멀티 스레드 인으로 전환 할 수 있다고 가정해야합니다.그 결과로, 당신은 항상 코드의 임계 영역에 대한 잠금을 사용해야합니다.

For library developers, it is unwise to create locks only when an application becomes multithreaded. If you need to lock your code at some point, create the lock object early in the use of your library, preferably in some sort of explicit call to initialize the library. Although you could also use a static library initialization function to create such locks, try to do so only when there is no other way. Execution of an initialization function adds to the time required to load your library and could adversely affect performance.

라이브러리 개발자를 들어, 응용 프로그램이 멀티 스레드가되고있는 경우에만 잠금을 생성하는 것은 현명합니다. 당신은 어떤 지점에서 코드를 잠글 필요하면 바람직 라이브러리를 초기화하는 명시적인 호출의 일종으로, 초기 라이브러리의 사용 잠금 개체를 만듭니다. 당신은 또한 잠금을 생성하는 정적 라이브러리 초기화 함수를 사용할 수 있지만, 다른 방법이없는 경우에만 그렇게하려고합니다.초기화 함수의 실행은 라이브러리를로드하고 성능에 부정적인 영향을 미칠 수있는 필요한 시간을 추가합니다.

If you are developing a Cocoa library, you can register as an observer for the NSWillBecomeMultiThreadedNotification if you want to be notified when the application becomes multithreaded. You should not rely on receiving this notification, though, as it might be dispatched before your library code is ever called.

당신은 코코아 라이브러리를 개발하는 경우 응용 프로그램이 다중 스레드 될 때 통지하려는 경우, 당신은 NSWillBecomeMultiThreadedNotification에 대한 관찰자로 등록 할 수 있습니다. 라이브러리 코드가 적 호출되기 전에가 전달 될 수도로서 당신은,하지만,이 알림 수신에 의존해서는 안됩니다.

Posted by 창업자닉군
,