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

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


Synchronization
동기화

The presence of multiple threads in an application opens up potential issues regarding safe access to resources from multiple threads of execution. Two threads modifying the same resource might interfere with each other in unintended ways. For example, one thread might overwrite another’s changes or put the application into an unknown and potentially invalid state. If you are lucky, the corrupted resource might cause obvious performance problems or crashes that are relatively easy to track down and fix. If you are unlucky, however, the corruption may cause subtle errors that do not manifest themselves until much later, or the errors might require a significant overhaul of your underlying coding assumptions.

응용 프로그램에서 여러 스레드의 존재는 여러 실행 스레드에서 리소스에 안전하게 접근에 대한 잠재적 인 문제를 엽니 다. 동일한 자원을 수정하는 두 개의 스레드가 의도하지 않은 방법으로 서로 간섭 할 수 있습니다. 예를 들어, 하나의 스레드가 다른 사람의 변경 내용을 덮어 쓸 수 있습니다 또는 알 수없는 잠재적으로 유효하지 않은 상태로 응용 프로그램을 넣어. 당신이 운이 좋다면, 손상된 자원은 분명 성능 문제 또는 아래로 추적하고 해결하기 위해 상대적으로 쉽게 충돌이 발생할 수 있습니다. 당신이 운이 있다면, 그러나, 손상이 될 때까지 더 이상 자신을 매니 페스트하지 않는 미묘한 오류가 발생할 수 있습니다, ​​또는 오류는 기본 코딩 가정의 중요한 정밀 검사가 필요할 수 있습니다.

When it comes to thread safety, a good design is the best protection you have. Avoiding shared resources and minimizing the interactions between your threads makes it less likely for those threads to interfere with each other. A completely interference-free design is not always possible, however. In cases where your threads must interact, you need to use synchronization tools to ensure that when they interact, they do so safely.

이 스레드 안전에 관해서는, 좋은 디자인은 당신이 가장 좋은 보호이다. 공유 리소스를 방지하고 스레드 간의 상호 작용을 최소화하는 것은 서로 방해하는 스레드가 덜합니다.완전 무료 간섭을 디자인하지만, 항상 가능한 것은 아닙니다. 귀하의 스레드가 상호 작용해야하는 경우에, 당신은 그들이 상호 작용할 때, 그들은 그렇게 안전하게 수행 할 수 있도록 동기화 도구를 사용해야합니다.

OS X and iOS provide numerous synchronization tools for you to use, ranging from tools that provide mutually exclusive access to those that sequence events correctly in your application. The following sections describe these tools and how you use them in your code to affect safe access to your program’s resources.

OS X 및 IOS는 사람들에게 상호 배타적 인 접근을 제공하는 도구에 이르기까지 귀하가 사용하는 다양한 동기화 도구를 제공하는 제대로 응용 프로그램에서 이벤트의 순서.에게다음 섹션에서는 이러한 도구를 설명하고 당신은 당신의 프로그램의 리소스에 안전하게 접근에 영향을 코드에서 사용하는 방법.

Synchronization Tools
동기화 도구

To prevent different threads from changing data unexpectedly, you can either design your application to not have synchronization issues or you can use synchronization tools. Although avoiding synchronization issues altogether is preferable, it is not always possible. The following sections describe the basic categories of synchronization tools available for you to use.

예기치 않게 데이터를 변경에서 다른 스레드를 방지하기 위해, 당신도 동기화 문제가되지 않도록 응용 프로그램을 설계하거나 동기화 도구를 사용할 수 있습니다. 동기화 문제를 방지하는 것은 모두 바람직하지만, 항상 그렇지는 않습니다.다음 섹션에서는 사용이 가능 동기화 도구의 기본 범주를 설명합니다.

Atomic Operations

원자 운영

Atomic operations are a simple form of synchronization that work on simple data types. The advantage of atomic operations is that they do not block competing threads. For simple operations, such as incrementing a counter variable, this can lead to much better performance than taking a lock.

원자 작업은 간단한 데이터 유형에 대한 해당 작업 동기화의 간단한 형태입니다. 원자 작업의 장점은 경쟁 스레드를 차단하지 않는 것입니다. 이러한 카운터 변수를 증가 같은 간단한 작업의 경우,이 잠금을 복용하는 것보다 훨씬 더 나은 성능을 초래할 수 있습니다.

OS X and iOS include numerous operations to perform basic mathematical and logical operations on 32-bit and 64-bit values. Among these operations are atomic versions of the compare-and-swap, test-and-set, and test-and-clear operations. For a list of supported atomic operations, see the/usr/include/libkern/OSAtomic.h header file or see the atomic man page.

OS X 및 IOS는 32 비트 및 64 비트 값에 대한 기본적인 수학 및 논리 연산을 수행하는 많은 작업을 이용하실 수 있습니다. 이러한 작업 사이 비교 및 스왑, 테스트 및 설정, 테스트 및 명확한 작업의 원자 버전입니다. 지원되는 원자 연산의 목록은 / usr / include와 / libkern / OSAtomic.h 헤더 파일을 참조하거나 원자 매뉴얼 페이지를 참조하십시오.

Memory Barriers and Volatile Variables

메모리 장벽 및 휘발성 변수

In order to achieve optimal performance, compilers often reorder assembly-level instructions to keep the instruction pipeline for the processor as full as possible. As part of this optimization, the compiler may reorder instructions that access main memory when it thinks doing so would not generate incorrect data. Unfortunately, it is not always possible for the compiler to detect all memory-dependent operations. If seemingly separate variables actually influence each other, the compiler optimizations could update those variables in the wrong order, generating potentially incorrect results.

최적의 성능을 달성하기 위해, 컴파일러는 가능한 한 자주 전체로 프로세서의 명령어 파이프 라인을 유지하기 위해 어셈블리 수준의 지침을 순서. 이러한 최적화의 일환으로, 컴파일러는 이렇게하면 잘못된 데이터를 생성하지 않을 생각하면 메인 메모리에 액세스하는 지침을 재정렬 할 수 있습니다. 불행히도, 모든 메모리에 의존하는 작업을 감지하는 컴파일러 항상 가능한 것은 아닙니다. 겉보기에 별도의 변수는 실제로 서로 영향을 미치는 경우, 컴파일러 최적화는 잠재적으로 잘못된 결과를 생성 잘못된 순서로 그 변수를 업데이트 할 수 있습니다.

A memory barrier is a type of nonblocking synchronization tool used to ensure that memory operations occur in the correct order. A memory barrier acts like a fence, forcing the processor to complete any load and store operations positioned in front of the barrier before it is allowed to perform load and store operations positioned after the barrier. Memory barriers are typically used to ensure that memory operations by one thread (but visible to another) always occur in an expected order. The lack of a memory barrier in such a situation might allow other threads to see seemingly impossible results. (For an example, see the Wikipedia entry formemory barriers.) To employ a memory barrier, you simply call the OSMemoryBarrier function at the appropriate point in your code.

메모리 장벽은 메모리 작업이 올바른 순서로 발생하는지 확인하는 데 사용되는 블로킹 동기화 도구의 유형입니다.메모리 장벽은 부하 장벽 뒤에 배치 저장 작업을 수행하도록 허용하기 전에 프로세서가 장벽 앞에 위치하는로드 및 저장 작업을 완료하도록 강요, 울타리 같은 역할을합니다. 메모리 장벽은 일반적으로 하나의 스레드 (그러나 다른 볼)에 의해 메모리 작업이 항상 예상 한 순서로 발생하는지 확인하는 데 사용됩니다. 이러한 상황에서 메모리 장벽의 부족은 다른 스레드가 불가능 해 보이는 결과를 볼 수 있습니다. (예를 들어, 위키 피 디아 항목 formemory 장벽을 참조하십시오.) 메모리 장벽을 적용하려면, 당신은 단순히 코드의 해당 지점에서 OSMemoryBarrier 함수를 호출합니다.

Volatile variables apply another type of memory constraint to individual variables. The compiler often optimizes code by loading the values for variables into registers. For local variables, this is usually not a problem. If the variable is visible from another thread however, such an optimization might prevent the other thread from noticing any changes to it. Applying the volatile keyword to a variable forces the compiler to load that variable from memory each time it is used. You might declare a variable as volatile if its value could be changed at any time by an external source that the compiler may not be able to detect.

휘발성 변수는 개별 변수의 메모리 제약 조건의 다른 유형을 적용합니다.컴파일러는 종종 레지스터에 변수 값을로드하여 코드를 최적화합니다. 지역 변수의 경우, 이것은 일반적으로 문제가되지 않습니다. 변수가 있지만 다른 스레드에서 볼 경우, 이러한 최적화는 어떤 변화를 알아 차리지에서 다른 스레드를 방지 할 수 있습니다.변수에 volatile 키워드를 적용하면 컴파일러는 메모리에서 사용 때마다 해당 변수를로드하도록합니다. 그 값이 컴파일러가 감지 할 수 없다는 외부 소스에 의해 언제든지 변경 될 수 있습니다 경우 volatile로 변수를 선언 할 수 있습니다.

Because both memory barriers and volatile variables decrease the number of optimizations the compiler can perform, they should be used sparingly and only where needed to ensure correctness. For information about using memory barriers, see the OSMemoryBarrier man page.

정확성을 보장하기 위해 필요한 곳에, 그들은 드물게 만 사용되어야한다. 메모리 장벽을 사용하는 방법에 대한 자세한 내용은 OSMemoryBarrier 매뉴얼 페이지를 참조하십시오.

Locks

자물쇠

Locks are one of the most commonly used synchronization tools. You can use locks to protect a critical section of your code, which is a segment of code that only one thread at a time is allowed access. For example, a critical section might manipulate a particular data structure or use some resource that supports at most one client at a time. By placing a lock around this section, you exclude other threads from making changes that might affect the correctness of your code.

잠금은 가장 일반적으로 사용되는 동기화 도구 중 하나입니다. 당신은 코드의 임계 영역을 보호하기 위해 잠금을 사용할 수있는 한 번에 하나의 스레드 만 액세스가 허용되는 코드 세그먼트입니다. 예를 들어, 임계 영역은 특정 데이터 구조를 조작하거나 한 번에 최대 하나의 클라이언트를 지원하는 일부 리소스를 사용할 수 있습니다. 이 섹션의 주위에 잠금을 배치함으로써, 당신은 당신의 코드의 정확성에 영향을 미칠 수있는 변경 사항을 다른 스레드를 제외한다.

Table 4-1 lists some of the locks that are commonly used by programmers. OS X and iOS provide implementations for most of these lock types, but not all of them. For unsupported lock types, the description column explains the reasons why those locks are not implemented directly on the platform.

표 4-1은 일반적으로 프로그래머에 의해 사용되는 잠금 중 일부를 나열합니다. OS X 및 IOS는이 잠금 유형의 대부분의 구현,하지만 그들 모두를 제공합니다. 지원되지 않는 잠금 유형에 대해 설명 열은 이러한 잠금 플랫폼에 직접 구현하지 않는 이유에 대해 설명합니다.

Table 4-1  Lock types

Lock

Description

Mutex

A mutually exclusive (or mutex) lock acts as a protective barrier around a resource. A mutex is a type of semaphore that grants access to only one thread at a time. If a mutex is in use and another thread tries to acquire it, that thread blocks until the mutex is released by its original holder. If multiple threads compete for the same mutex, only one at a time is allowed access to it.

상호 배타적 (또는 뮤텍스) 잠금 리소스의 주위에 보호 장벽 역할을합니다.뮤텍스는 한 번에 하나의 스레드에 대한 액세스 권한을 부여 세마포어의 유형입니다.뮤텍스를 사용하고 다른 스레드가 그것을 취득하려고하면 스레드가 차단되는 뮤텍스가 원래 소유자가 해제 될 때까지. 여러 스레드가 같은 뮤텍스에 대해 경쟁하는 경우, 한 번에 하나에 대한 액세스를 허용합니다.

Recursive lock

A recursive lock is a variant on the mutex lock. A recursive lock allows a single thread to acquire the lock multiple times before releasing it. Other threads remain blocked until the owner of the lock releases the lock the same number of times it acquired it. Recursive locks are used during recursive iterations primarily but may also be used in cases where multiple methods each need to acquire the lock separately.

재귀 잠금 뮤텍스 잠금 변종이다.재귀 잠금을 해제하기 전에 잠금을 여러 번 획득 할 수있는 단일 스레드를 할 수 있습니다.잠금의 소유자가 잠금에게 그것을 획득 동일한 횟수를 해제 할 때까지 다른 스레드가 차단 남아있다. 재귀 잠금은 기본적으로 재귀 반복하는 동안 사용되지만 여러 방법을 각각 개별적으로 잠금을 획득해야하는 곳도 경우에 사용할 수 있습니다.

Read-write lock

A read-write lock is also referred to as a shared-exclusive lock. This type of lock is typically used in larger-scale operations and can significantly improve performance if the protected data structure is read frequently and modified only occasionally. During normal operation, multiple readers can access the data structure simultaneously. When a thread wants to write to the structure, though, it blocks until all readers release the lock, at which point it acquires the lock and can update the structure. While a writing thread is waiting for the lock, new reader threads block until the writing thread is finished. The system supports read-write locks using POSIX threads only. For more information on how to use these locks, see thepthread man page.

읽기 - 쓰기 잠금은 공유 배타적 잠금이라고합니다. 이러한 유형의 잠금은 일반적으로 대규모 작업에 사용되며, 보호 된 데이터 구조가 자주 읽고 가끔 변경되는 경우 성능을 크게 향상시킬 수 있습니다. 정상 작동 중에 여러 독자들이 동시에 데이터 구조에 액세스 할 수 있습니다.스레드 구조를 작성하고자 할 때,하지만, 그 블록은 모든 독자 때까지 잠금을 획득하고 구조를 업데이트 할 수있는 시점에서 잠금을 해제.쓰기 스레드가 완료 될 때까지 쓰기 스레드는 잠금 새로운 리더 스레드 블록을 기다리는 동안.시스템이 POSIX 스레드 만 사용하여 읽기 - 쓰기 잠금을 지원합니다. 이러한 잠금을 사용하는 방법에 대한 자세한 내용은 thepthread 매뉴얼 페이지를 참조하십시오.

Distributed lock

A distributed lock provides mutually exclusive access at the process level. Unlike a true mutex, a distributed lock does not block a process or prevent it from running. It simply reports when the lock is busy and lets the process decide how to proceed.

분산 잠금 프로세스 수준에서 상호 배타적 인 액세스를 제공합니다. 진정한 뮤텍스는 달리, 분산 잠금은 프로세스를 차단하지 못하거나 실행을 방지합니다. 잠금이 사용 중이고 과정이 진행 방법을 결정할 수 있습니다 때 그것은 단순히보고합니다.

Spin lock

A spin lock polls its lock condition repeatedly until that condition becomes true. Spin locks are most often used on multiprocessor systems where the expected wait time for a lock is small. In these situations, it is often more efficient to poll than to block the thread, which involves a context switch and the updating of thread data structures. The system does not provide any implementations of spin locks because of their polling nature, but you can easily implement them in specific situations. For information on implementing spin locks in the kernel, see Kernel Programming Guide.

대부분 잠금 예상 대기 시간이 작은 멀티 프로세서 시스템에서 사용됩니다. 이러한 상황에서는, 그것은 종종 컨텍스트 스위치 및 스레드 데이터 구조의 업데이트를 포함 스레드를 차단하는 것보다 투표에 더 효율적입니다.시스템이 있기 때문에 자신의 폴링 자연의 스핀 락의 구현을 제공하지 않습니다,하지만 당신은 쉽게 특정 상황에서 그들을 구현할 수 있습니다.커널에서 스핀 락을 구현하는 방법에 대한 자세한 내용은 커널 프로그래밍 가이드를 참조하십시오.

Double-checked lock

A double-checked lock is an attempt to reduce the overhead of taking a lock by testing the locking criteria prior to taking the lock. Because double-checked locks are potentially unsafe, the system does not provide explicit support for them and their use is discouraged.

이중 확인 잠금 장치는 잠금을 복용하기 전에 잠금 조건을 테스트하여 잠금을 복용의 오버 헤드를 줄이기 위해 시도이다. 이중 확인 잠금 안전하지 않기 때문에, 시스템은 그들을 위해 명시 적으로 지원을 제공하지 않으며 사용하지 않는 것이 좋습니다.

For information on how to use locks, see “Using Locks.”

잠금을 사용하는 방법에 대한 자세한 내용은 "잠금 사용"을 참조하십시오.

Conditions

조건

A condition is another type of semaphore that allows threads to signal each other when a certain condition is true. Conditions are typically used to indicate the availability of a resource or to ensure that tasks are performed in a specific order. When a thread tests a condition, it blocks unless that condition is already true. It remains blocked until some other thread explicitly changes and signals the condition. The difference between a condition and a mutex lock is that multiple threads may be permitted access to the condition at the same time. The condition is more of a gatekeeper that lets different threads through the gate depending on some specified criteria.

조건은 특정 조건이 true 일 때 스레드가 서로 신호를 할 수 있습니다 세마포어의 또 다른 유형입니다. 조건은 일반적으로 자원의 가용성을 나타 내기 위해 또는 작업이 특정 순서로 수행되는 것을 보장하기 위해 사용됩니다. 해당 조건 않는 스레드가 조건을 테스트, 그것은 블록은 이미 사실이다. 그것은 다른 스레드 명시 적 변화와 신호 상태가 될 때까지 차단 남아있다.상태와 뮤텍스 잠금의 차이점은 여러 스레드가 동시에 상태에 대한 액세스를 허용 할 수 있다는 것입니다.조건은 몇 가지 특정 기준에 따라 게이트를 통해 다른 스레드를 할 수있는 게이트 키퍼의 이상입니다.

One way you might use a condition is to manage a pool of pending events. The event queue would use a condition variable to signal waiting threads when there were events in the queue. If one event arrives, the queue would signal the condition appropriately. If a thread were already waiting, it would be woken up whereupon it would pull the event from the queue and process it. If two events came in to the queue at roughly the same time, the queue would signal the condition twice to wake up two threads.

당신이 조건을 사용할 수있는 방법 중 하나는 보류중인 이벤트의 풀을 관리하는 것입니다.이벤트 큐는 큐에 이벤트가있을 때 대기중인 스레드에 신호를 조건 변수를 사용합니다. 하나의 이벤트가 도착하면 대기열이 적절하게 조건을 신호합니다.스레드가 이미 기다리고 있었다 경우는 큐로부터 이벤트를 당겨하고 처리 할 그러자, 그것은 깨어 될 것이다. 두 사건이 거의 동시에 큐에 온 경우, 대기열은 두 개의 스레드를 깨워 두 조건을 신호합니다.

The system provides support for conditions in several different technologies. The correct implementation of conditions requires careful coding, however, so you should look at the examples in “Using Conditions” before using them in your own code.

이 시스템은 여러 가지 기술 조건에 대한 지원을 제공합니다. 조건의 올바른 구현은주의 코딩이 필요하지만, 그래서 당신은 당신의 자신의 코드를 사용하기 전에 "조건 사용"의 예를 살펴해야합니다.

Perform Selector Routines

선택 루틴을 수행

Cocoa applications have a convenient way of delivering messages in a synchronized manner to a single thread. The NSObject class declares methods for performing a selector on one of the application’s active threads. These methods let your threads deliver messages asynchronously with the guarantee that they will be performed synchronously by the target thread. For example, you might use perform selector messages to deliver results from a distributed computation to your application’s main thread or to a designated coordinator thread. Each request to perform a selector is queued on the target thread’s run loop and the requests are then processed sequentially in the order in which they were received.

코코아 응용 프로그램은 단일 스레드에 동기화 된 방식으로 메시지를 전달하는 편리한 방법이 있습니다.NSObject의 클래스는 응용 프로그램의 활성 스레드 중 하나에서 선택을 수행하는 방법을 선언합니다. 이러한 방법은 스레드들이 대상 스레드에 의해 동시에 수행 될 것을 보장 비동기 적으로 메시지를 전달 할 수 있습니다. 예를 들어, 응용 프로그램의 주 스레드 또는 지정된 코디네이터 스레드에 분산 계산의 결과를 제공하기 위해 수행 선택 메시지를 사용할 수 있습니다.선택기를 수행하는 각 요청은 대상 스레드의 실행 루프에서 대기하고 요청은 그들이받은 순서에 따라 순차적으로 처리됩니다.

For a summary of perform selector routines and more information about how to use them, see “Cocoa Perform Selector Sources.”

선택 루틴을 사용하는 방법에 대한 자세한 내용을 수행의 요약은 "코코아 선택기 소스를 수행"을 참조하십시오.

Synchronization Costs and Performance
동기화 비용 및 성능

Synchronization helps ensure the correctness of your code, but does so at the expense of performance. The use of synchronization tools introduces delays, even in uncontested cases. Locks and atomic operations generally involve the use of memory barriers and kernel-level synchronization to ensure code is properly protected. And if there is contention for a lock, your threads could block and experience even greater delays.

동기화 코드의 정확성을 보장 할 수 있지만 성능의 비용으로 그렇게 않습니다. 동기화 도구의 사용도 명백한 경우에, 지연을 소개합니다. 잠금 및 원자 작업은 일반적으로 코드가 적절히 보호되는지 확인하여 메모리 장벽과 커널 레벨의 동기화의 사용을 포함한다.잠금 경합이있는 경우, 귀하의 스레드를 차단하고 더 큰 지연이 발생할 수 있습니다.

Table 4-2 lists some of the approximate costs associated with mutexes and atomic operations in the uncontested case. These measurements represented average times taken over several thousand samples. As with thread creation times though, mutex acquisition times (even in the uncontested case) can vary greatly depending on processor load, the speed of the computer, and the amount of available system and program memory.

표 4-2 명백한 경우에 뮤텍스 원자 운영과 관련된 대략적인 비용의 일부를 보여줍니다. 이 측정은 몇 천 샘플을 점령 평균 시간을 나타낸다. 하지만 스레드 생성 시간과 마찬가지로, 뮤텍스 획득 시간 (심지어 명백한 경우)는 프로세서 부하, 컴퓨터의 속도 및 사용 가능한 시스템 및 프로그램 메모리의 양에 따라 크게 달라질 수 있습니다.

Table 4-2  Mutex and atomic operation costs

Item

Approximate cost

Notes

Mutex acquisition time

Approximately 0.2 microseconds

This is the lock acquisition time in an uncontested case. If the lock is held by another thread, the acquisition time can be much greater. The figures were determined by analyzing the mean and median values generated during mutex acquisition on an Intel-based iMac with a 2 GHz Core Duo processor and 1 GB of RAM running OS X v10.5.

이 명백한 경우 잠금 수집 시간입니다.락이 다른 thread에 의해 보관 유지되고있는 경우, 수집 시간은 훨씬 클 수 있습니다.수치는 OS X 10.5을 실행 2 GHz의 코어 듀오 프로세서와 1GB의 RAM과 인텔 기반 아이맥에 뮤텍스를 수집 중에 생성 된 평균과 중간 값을 분석하여 결정 하였다.

Atomic compare-and-swap

Approximately 0.05 microseconds

This is the compare-and-swap time in an uncontested case. The figures were determined by analyzing the mean and median values for the operation and were generated 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과 인텔 기반 아이맥에서 생성되었다.

When designing your concurrent tasks, correctness is always the most important factor, but you should also consider performance factors as well. Code that executes correctly under multiple threads, but slower than the same code running on a single thread, is hardly an improvement.

귀하의 동시 작업을 설계 할 때 정확성은 항상 가장 중요한 요소입니다,하지만 당신은 또한뿐만 아니라 성능 요인을 고려해야합니다. 여러 스레드에서 제대로 실행하지만 단일 스레드에서 실행되는 동일한 코드보다 느린 코드는 거의 개선되지 않습니다.

If you are retrofitting an existing single-threaded application, you should always take a set of baseline measurements of the performance of key tasks. Upon adding additional threads, you should then take new measurements for those same tasks and compare the performance of the multithreaded case to the single-threaded case. If after tuning your code, threading does not improve performance, you may want to reconsider your specific implementation or the use of threads altogether.

기존 단일 스레드 응용 프로그램을 개조하는 경우, 당신은 항상 주요 작업의 성능 기준 측정 세트를 취해야한다. 추가 스레드를 추가 후, 당신은 그 그 같은 작업을 위해 새로운 측정을 수행해야하며, 단일 스레드 케이스에 멀티 스레드 사건의 성능을 비교. 코드를 조정 한 후, 스레딩 성능이 향상되지 않을 경우, 당신은 모두 특정 구현 또는 스레드의 사용을 재고 할 수 있습니다.

For information about performance and the tools for gathering metrics, see Performance Overview. For specific information about the cost of locks and atomic operations, see “Thread Costs.”

성능에 대한 정보를 수집 메트릭 도구, 성능 개요를 참조하십시오. 잠금 및 원자 운영 비용에 대한 자세한 내용은 "스레드 비용"을 참조하십시오.

Thread Safety and Signals
스레드로부터의 안전성 및 신호

When it comes to threaded applications, nothing causes more fear or confusion than the issue of handling signals. Signals are a low-level BSD mechanism that can be used to deliver information to a process or manipulate it in some way. Some programs use signals to detect certain events, such as the death of a child process. The system uses signals to terminate runaway processes and communicate other types of information.

이 스레드 응용 프로그램에 올 때, 아무것도 신호를 처리하는 문제보다 더 두려움이나 혼란을 발생하지 않습니다. 신호는 어떤 방법으로 프로세스에 정보를 제공하거나 조작하는 데 사용할 수있는 낮은 수준의 BSD 메커니즘입니다. 일부 프로그램은 자식 프로세스의 죽음과 같은 특정 이벤트를 감지하는 신호를 사용합니다. 이 시스템은 가출 프로세스를 종료하고 다른 유형의 정보를 전달하는 신호를 사용합니다.

The problem with signals is not what they do, but their behavior when your application has multiple threads. In a single-threaded application, all signal handlers run on the main thread. In a multithreaded application, signals that are not tied to a specific hardware error (such as an illegal instruction) are delivered to whichever thread happens to be running at the time. If multiple threads are running simultaneously, the signal is delivered to whichever one the system happens to pick. In other words, signals can be delivered to any thread of your application.

응용 프로그램이 여러 스레드가있을 때 신호와 문제는 그들이 무엇 아니라, 그들의 행동.단일 스레드 응용 프로그램에서 모든 신호 핸들러는 주 스레드에서 실행됩니다.다중 스레드 응용 프로그램에서 특정 하드웨어 오류 (예 : 잘못된 명령 등)에 연결되지 않은 신호는 어느 스레드가 동시에 실행하는 일에 전달됩니다. 여러 스레드가 동시에 실행하는 경우, 신호는 어느 시스템을 선택하는 일이 하나 전달됩니다. 즉, 신호는 응용 프로그램의 모든 스레드에 전달 될 수 있습니다.

The first rule for implementing signal handlers in applications is to avoid assumptions about which thread is handling the signal. If a specific thread wants to handle a given signal, you need to work out some way of notifying that thread when the signal arrives. You cannot just assume that installation of a signal handler from that thread will result in the signal being delivered to the same thread.

응용 프로그램에서 시그널 핸들러를 구현하기위한 첫 번째 규칙은 신호를 처리하는 스레드에 대한 가정을하지 않도록하는 것입니다.특정 스레드가 특정 신호를 처리하고자하는 경우, 당신은 신호가 도착할 때 해당 스레드를 알리는 몇 가지 방법을 해결해야합니다. 당신은 그 스레드에서 신호 처리기의 설치가 동일한 스레드에 전달되는 신호가 될 것이라고 가정 할 수 없습니다.

For more information about signals and installing signal handlers, see signal and sigaction man pages.
신호 및 설치 시그널 핸들러에 대한 자세한 내용은 신호를 sigaction 매뉴얼 페이지를 참조하십시오.

Tips for Thread-Safe Designs
스레드로부터 안전한 설계를위한 팁

Synchronization tools are a useful way to make your code thread-safe, but they are not a panacea. Used too much, locks and other types of synchronization primitives can actually decrease your application’s threaded performance compared to its non-threaded performance. Finding the right balance between safety and performance is an art that takes experience. The following sections provide tips to help you choose the appropriate level of synchronization for your application.

동기화 도구는 코드가 스레드 안전 만들 수있는 유용한 방법입니다,하지만 그들은 만병 통치약이 아닙니다. 너무 많이 사용, 잠금 및 동기화 프리미티브의 다른 유형은 실제로는 비 스레드 성능에 비해 응용 프로그램의 스레드 성능이 저하 될 수 있습니다. 안전과 성능 사이의 올바른 균형을 찾는 경험을 걸립니다 예술이다.다음 섹션에서는 응용 프로그램의 동기화의 적절한 수준을 선택할 수 있도록 팁을 제공합니다.

Avoid Synchronization Altogether

전부 동기화 방지하기

For any new projects you work on, and even for existing projects, designing your code and data structures to avoid the need for synchronization is the best possible solution. Although locks and other synchronization tools are useful, they do impact the performance of any application. And if the overall design causes high contention among specific resources, your threads could be waiting even longer.

당신은 동기화의 필요성을 피하기 위해 코드와 데이터 구조를 설계, 기존 프로젝트에도 작업과 새로운 프로젝트에 대한 최상의 솔루션입니다. 잠금 및 다른 동기화 도구는 유용하지만, 그들은 어떤 응용 프로그램의 성능에 영향을 미칠 않습니다.전체적인 디자인은 특정 리소스 사이에서 경합이 발생하면, 당신의 스레드가 더 오래 대기 할 수 있습니다.

The best way to implement concurrency is to reduce the interactions and inter-dependencies between your concurrent tasks. If each task operates on its own private data set, it does not need to protect that data using locks. Even in situations where two tasks do share a common data set, you can look at ways of partitioning that set or providing each task with its own copy. Of course, copying data sets has its costs too, so you have to weigh those costs against the costs of synchronization before making your decision.

동시성을 구현하는 가장 좋은 방법은 동시 작업 간의 상호 작용과 상호 의존성을 줄이는 것입니다. 각 작업이 설정된 자신의 개인 데이터를 작동하면 잠금을 사용하여 해당 데이터를 보호 할 필요가 없습니다. 심지어 두 작업은 공통된 데이터 집합을 경우에, 그 집합을 분할하거나 자신의 복사본을 각 작업을 제공하는 방법을 볼 수 있습니다. 물론, 데이터 집합을 복사하는도 그 비용이, 당신이 결정을하기 전에 동기화의 비용에 대하여 그 비용의 무게를해야합니다 그래서.

Understand the Limits of Synchronization

동기화의 한계를 이해

Synchronization tools are effective only when they are used consistently by all threads in an application. If you create a mutex to restrict access to a specific resource, all of your threads must acquire the same mutex before trying to manipulate the resource. Failure to do so defeats the protection offered by the mutex and is a programmer error.

그들은 응용 프로그램의 모든 스레드에 의해 일관되게 사용하는 경우에만 동기화 도구가 효과적입니다. 특정 리소스에 대한 액세스를 제한하는 뮤텍스를 만들 경우, 모든 스레드는 리소스를 조작하기 전에 동일한 뮤텍스를 취득해야합니다. 그렇지 않으면 뮤텍스에 의해 제공되며 프로그래머 오류가 보호를 패배.

Be Aware of Threats to Code Correctness

코드 정확성에 대한 위협으로 인식 될

When using locks and memory barriers, you should always give careful thought to their placement in your code. Even locks that seem well placed can actually lull you into a false sense of security. The following series of examples attempt to illustrate this problem by pointing out the flaws in seemingly innocuous code. The basic premise is that you have a mutable array containing a set of immutable objects. Suppose you want to invoke a method of the first object in the array. You might do so using the following code:

잠금 및 메모리 장벽을 사용하는 경우, 당신은 항상 당신의 코드에서 자신의 위치에주의 생각을 주어야한다. 절묘한 것조차 잠금 보안 거짓 감각에 실제로 소강를 할 수 있습니다. 예제 다음 시리즈는 겉보기에 무해한 코드의 결함을 지적하여이 문제를 설명하기 위해 시도합니다.기본 전제는 불변의 객체의 집합을 포함하는 가변 배열을 가지고있다. 당신은 배열의 첫 번째 개체의 메서드를 호출한다고 가정합니다. 다음 코드를 사용하여 그렇게 할 수 있습니다 :

NSLock* arrayLock = GetArrayLock();
NSMutableArray* myArray = GetSharedArray();
id anObject;
 
[arrayLock lock];
anObject = [myArray objectAtIndex:0];
[arrayLock unlock];
 
[anObject doSomething];

Because the array is mutable, the lock around the array prevents other threads from modifying the array until you get the desired object. And because the object you retrieve is itself immutable, a lock is not needed around the call to the doSomething method.

배열이 변하기 때문에, 배열의 주위에 잠금을 원하는 객체를 얻을 때까지 배열을 수정하는 다른 스레드를 방지 할 수 있습니다. 당신이 검색하는 객체는 불변 자체이기 때문에, 잠금 해봐요 메서드에 대한 호출 주위에 필요하지 않습니다.

There is a problem with the preceding example, though. What happens if you release the lock and another thread comes in and removes all objects from the array before you have a chance to execute the doSomething method? In an application without garbage collection, the object your code is holding could be released, leaving anObject pointing to an invalid memory address. To fix the problem, you might decide to simply rearrange your existing code and release the lock after your call to doSomething, as shown here:

앞의 예에 문제가 있긴 있습니다. 당신이 해봐요 메서드를 실행하는 기회를 갖기도 전에 배열에서 모든 개체를 잠금을 해제하고 다른 스레드가 들어오고 삭제하면 어떻게됩니까? 가비지 수집이없는 응용 프로그램에서 코드를 잡고 개체는 anObject가 잘못된 메모리 주소를 가리키는 남겨 해제 할 수 있습니다. 이 문제를 해결하려면, 당신은 여기에 표시된대로, 단순히 기존의 코드를 재 배열 해봐요로하여 호출 한 후 잠금을 해제하도록 결정할 수 있습니다 :

NSLock* arrayLock = GetArrayLock();
NSMutableArray* myArray = GetSharedArray();
id anObject;
 
[arrayLock lock];
anObject = [myArray objectAtIndex:0];
[anObject doSomething];
[arrayLock unlock];

By moving the doSomething call inside the lock, your code guarantees that the object is still valid when the method is called. Unfortunately, if the doSomethingmethod takes a long time to execute, this could cause your code to hold the lock for a long time, which could create a performance bottleneck.

잠금 장치 내부 해봐요 통화를 이동하여, 코드 메서드가 호출 될 때 객체가 여전히 유효하다는 것을 보장합니다.doSomethingmethod을 실행하는 데 시간이 오래 걸리는 경우에 불행히도,이 성능 병목 현상을 만들 수 있습니다 긴 시간 동안 잠금을 보유하도록 코드를 발생할 수 있습니다.

The problem with the code is not that the critical region was poorly defined, but that the actual problem was not understood. The real problem is a memory management issue that is triggered only by the presence of other threads. Because it can be released by another thread, a better solution would be to retainanObject before releasing the lock. This solution addresses the real problem of the object being released and does so without introducing a potential performance penalty.

코드 문제는 중요한 영역이 제대로 정의하는 것이 아니라 실제 문제는 이해되지 않았 음.진짜 문제는 다른 스레드의 존재에 의해 트리거되는 메모리 관리 문제입니다. 그것은 다른 스레드에 의해 해제 될 수 있기 때문에, 더 나은 솔루션을 잠금을 해제하기 전에 retainanObject하는 것입니다. 이 솔루션은 개체가 해제되는 실제 문제를 해결하고 잠재적 인 성능 저하를 도입하지 않고이를 수행.

NSLock* arrayLock = GetArrayLock();
NSMutableArray* myArray = GetSharedArray();
id anObject;
 
[arrayLock lock];
anObject = [myArray objectAtIndex:0];
[anObject retain];
[arrayLock unlock];
 
[anObject doSomething];
[anObject release];

Although the preceding examples are very simple in nature, they do illustrate a very important point. When it comes to correctness, you have to think beyond the obvious problems. Memory management and other aspects of your design may also be affected by the presence of multiple threads, so you have to think about those problems up front. In addition, you should always assume that the compiler will do the worst possible thing when it comes to safety. This kind of awareness and vigilance should help you avoid potential problems and ensure that your code behaves correctly.

앞의 예는 자연에서 매우 간단하지만, 그들은 매우 중요한 점을 설명 않습니다. 그것은 정확성에 올 때, 당신은 분명 문제를 넘어 생각해야합니다. 메모리 관리 및 디자인의 다른 측면은 여러 스레드의 존재에 의해 영향을받는, 그래서 당신은 눈 앞에 그 문제에 대해 생각해야 할 수 있습니다. 또한, 당신은 항상 안전에 올 때 컴파일러는 최악의 일을 할 것이라고 가정해야합니다. 인식과 경계의이 종류는 당신이 잠재적 인 문제를 방지하고 코드가 제대로 동작하는지 확인하는 데 도움이됩니다.

For additional examples of how to make your program thread-safe, see “Thread Safety Summary.”
프로그램은 스레드 안전 만드는 방법의 다른 예를 들어, "스레드 안전 요약"을 참조하십시오.

Watch Out for Deadlocks and Livelocks

교착 상태와 Livelocks에 대한 조심

Any time a thread tries to take more than one lock at the same time, there is a potential for a deadlock to occur. A deadlock occurs when two different threads hold a lock that the other one needs and then try to acquire the lock held by the other thread. The result is that each thread blocks permanently because it can never acquire the other lock.

스레드가 동시에 하나 이상의 잠금을 시도하는 시간이 발생하는 교착 상태 가능성이 있습니다. 두 개의 서로 다른 스레드가 다른 하나의 요구와 다음이 다른 thread에 의해 보관 유지 잠금을 획득하려고하는 잠금을 보유하면 교착 상태가 발생합니다.결과는 다른 잠금을 획득 할 수 없다 때문에 각 스레드가 영구적으로 차단하는 것입니다.

A livelock is similar to a deadlock and occurs when two threads compete for the same set of resources. In a livelock situation, a thread gives up its first lock in an attempt to acquire its second lock. Once it acquires the second lock, it goes back and tries to acquire the first lock again. It locks up because it spends all its time releasing one lock and trying to acquire the other lock rather than doing any real work.

라이브 락은 교착 상태와 유사하며 두 스레드가 자원의 동일한 집합을 위해 경쟁 할 때 발생합니다.라이브 락 상황에서 스레드가 두 번째 잠금을 얻기 위해 시도의 첫 번째 잠금을 제공합니다. 일단은, 두 번째 잠금을 획득 해 다시 이동하고 다시 첫 번째 잠금을 획득하려고 시도합니다. 그것은 하나의 잠금을 해제하고 오히려 어떤 실제 작업을 수행하는 것보다 다른 잠금을 획득하려고 모든 시간을 보낸다 때문에 잠 깁니다.

The best way to avoid both deadlock and livelock situations is to take only one lock at a time. If you must acquire more than one lock at a time, you should make sure that other threads do not try to do something similar.

모두 교착 상태와 라이브 락 상황을 방지하는 가장 좋은 방법은 한 번에 하나의 잠금을하는 것입니다. 한 번에 하나 이상의 잠금을 획득해야하는 경우, 당신은 다른 스레드와 비슷한 뭔가를 시도하지 않도록해야합니다.

Use Volatile Variables Correctly

올바르게 휘발성 변수를 사용하여

If you are already using a mutex to protect a section of code, do not automatically assume you need to use the volatile keyword to protect important variables inside that section. A mutex includes a memory barrier to ensure the proper ordering of load and store operations. Adding the volatile keyword to a variable within a critical section forces the value to be loaded from memory each time it is accessed. The combination of the two synchronization techniques may be necessary in specific cases but also leads to a significant performance penalty. If the mutex alone is enough to protect the variable, omit the volatile keyword.

이미 코드 섹션을 보호하기 위해 뮤텍스를 사용하는 경우, 자동으로 해당 섹션 내부에 중요한 변수를 보호하기 위해 volatile 키워드를 사용할 필요가 생각하지 않습니다.뮤텍스는로드 및 저장 작업의 올바른 순서를 보장하기 위해 메모리 장벽을 포함합니다.중요 섹션에서 변수에 volatile 키워드를 추가하면 값이 메모리에서 액세스 할 때마다로드 할 수 강제로.두 개의 동기화 기술의 조합은 특정 경우에 필요하지만 성능이 크게 저하에 이르게 할 수 있습니다. 혼자 뮤텍스가 변수를 보호하기에 충분한 경우 volatile 키워드를 생략합니다.

It is also important that you do not use volatile variables in an attempt to avoid the use of mutexes. In general, mutexes and other synchronization mechanisms are a better way to protect the integrity of your data structures than volatile variables. The volatile keyword only ensures that a variable is loaded from memory rather than stored in a register. It does not ensure that the variable is accessed correctly by your code.

그것은 당신이 뮤텍스의 사용을 피하기 위해 시도 휘발성 변수를 사용하지 않는 것이 중요하다. 일반적으로, 뮤텍스 및 다른 동기화 메커니즘은 휘발성 변수보다 데이터 구조의 무결성을 보호하기 위해 더 나은 방법입니다.volatile 키워드는 변수가 메모리에서로드가 아닌 레지스터에 저장되어 있는지 확인합니다. 그것은 변수가 코드를 올바르게 액세스 할 수 있는지 확인하지 않습니다.

Using Atomic Operations
원자 연산을 사용하여

Nonblocking synchronization is a way to perform some types of operations and avoid the expense of locks. Although locks are an effective way to synchronize two threads, acquiring a lock is a relatively expensive operation, even in the uncontested case. By contrast, many atomic operations take a fraction of the time to complete and can be just as effective as a lock.

블로킹 동기화 작업의 일부 유형을 수행하고 잠금 비용을 방지하는 방법입니다. 잠금이 있지만 잠금을 획득, 두 개의 스레드를 동기화하는 효과적인 방법도 명백한 경우에, 상대적으로 비용이 많이 드는 작업이다. 대조적으로, 많은 원자 작업을 완료하는 시간의 비율을 가지고 잠금만큼 효과적 일 수 있습니다.

Atomic operations let you perform simple mathematical and logical operations on 32-bit or 64-bit values. These operations rely on special hardware instructions (and an optional memory barrier) to ensure that the given operation completes before the affected memory is accessed again. In the multithreaded case, you should always use the atomic operations that incorporate a memory barrier to ensure that the memory is synchronized correctly between threads.

원자 연산은 32 비트 또는 64 비트 값에 대한 간단한 수학 및 논리 연산을 수행 할 수 있습니다. 이러한 작업은 영향을받는 메모리가 다시 액세스하기 전에 주어진 작업이 완료되었는지 확인하기 위해 특별한 하드웨어 명령 (및 옵션 메모리 장벽)에 의존합니다.멀티 스레드 경우에, 당신은 항상 메모리가 스레드간에 제대로 동기화되었는지 확인하기 위해 메모리 장벽을 통합 원자 연산을 사용합니다.

Table 4-3 lists the available atomic mathematical and logical operations and the corresponding function names. These functions are all declared in the/usr/include/libkern/OSAtomic.h header file, where you can also find the complete syntax. The 64-bit versions of these functions are available only in 64-bit processes.

표 4-3는 사용 가능한 원자 수학 및 논리 연산과 해당 함수 이름을 나열합니다. 이러한 기능은 모든 당신의 전체 구문도 찾을 수는 / usr / include와 / libkern / OSAtomic.h 헤더 파일에 선언되어있다. 이 함수의 64 비트 버전은 64 비트 프로세스에서 사용할 수 있습니다.

Table 4-3  Atomic math and logic operations

Operation

Function name

Description

Add

OSAtomicAdd32

OSAtomicAdd32Barrier

OSAtomicAdd64

OSAtomicAdd64Barrier

Adds two integer values together and stores the result in one of the specified variables.

두 개의 정수 값을 추가하고 지정된 변수 중 하나에 결과를 저장합니다.

Increment

OSAtomicIncrement32

OSAtomicIncrement32Barrier

OSAtomicIncrement64

OSAtomicIncrement64Barrier

Increments the specified integer value by 1.

1 씩 증가는 지정된 정수 값입니다.

Decrement

OSAtomicDecrement32

OSAtomicDecrement32Barrier

OSAtomicDecrement64

OSAtomicDecrement64Barrier

Decrements the specified integer value by 1.

1 씩 감소는 지정된 정수 값입니다.

Logical OR

OSAtomicOr32

OSAtomicOr32Barrier

Performs a logical OR between the specified 32-bit value and a 32-bit mask.

논리 OR 지정된 32 비트 값과 32 비트 마스크 사이를 수행합니다.

Logical AND

OSAtomicAnd32

OSAtomicAnd32Barrier

Performs a logical AND between the specified 32-bit value and a 32-bit mask.

논리적 AND 지정된 32 비트 값과 32 비트 마스크 사이를 수행합니다.

Logical XOR

OSAtomicXor32

OSAtomicXor32Barrier

Performs a logical XOR between the specified 32-bit value and a 32-bit mask.

지정된 32 비트 값과 32 비트 마스크 사이에 논리적 XOR을 수행합니다.

Compare and swap

OSAtomicCompareAndSwap32

OSAtomicCompareAndSwap32Barrier

OSAtomicCompareAndSwap64

OSAtomicCompareAndSwap64Barrier

OSAtomicCompareAndSwapPtr

OSAtomicCompareAndSwapPtrBarrier

OSAtomicCompareAndSwapInt

OSAtomicCompareAndSwapIntBarrier

OSAtomicCompareAndSwapLong

OSAtomicCompareAndSwapLongBarrier

Compares a variable against the specified old value. If the two values are equal, this function assigns the specified new value to the variable; otherwise, it does nothing. The comparison and assignment are done as one atomic operation and the function returns a Boolean value indicating whether the swap actually occurred.

지정된 이전 값에 대한 변수를 비교합니다. 두 값이 동일한 경우,이 함수는 변수에 지정된 새 값을 할당하고, 그렇지 않으면 아무것도하지 않는다.비교 및 할당은 하나의 원자 단위 연산으로 수행하고 함수는 스왑이 실제로 발생했는지 여부를 나타내는 부울 값을 반환합니다.

Test and set

OSAtomicTestAndSet

OSAtomicTestAndSetBarrier

Tests a bit in the specified variable, sets that bit to 1, and returns the value of the old bit as a Boolean value. Bits are tested according to the formula (0x80 >> (n & 7)) of byte ((char*)address + (n >> 3)) where n is the bit number and address is a pointer to the variable. This formula effectively breaks up the variable into 8-bit sized chunks and orders the bits in each chunk in reverse. For example, to test the lowest-order bit (bit 0) of a 32-bit integer, you would actually specify 7 for the bit number; similarly, to test the highest order bit (bit 32), you would specify 24 for the bit number.

테스트 지정된 변수의 비트를 1로 그 비트를 설정하고 부울 값으로 이전 비트의 값을 반환합니다. 비트 n은 비트 수이며, 주소는 변수에 대한 포인터 바이트의 식 (0x80에 >> (N & 7)) ((char *로) 주소 + (N >> 3))에 따라 시험한다. 이 공식은 효과적으로 8 비트 크기의 청크 및 주문 반대로 각 청크의 비트에 변수를 나눕니다. 예를 들어, 32 비트 정수의 최하위 비트 (0 비트)를 테스트하기 위해, 당신은 실제로 비트 번호 7을 지정합니다, 마찬가지로 높은 순서 비트 (32 비트)를 테스트하려면 24을 지정합니다 비트 번호입니다.

Test and clear

OSAtomicTestAndClear

OSAtomicTestAndClearBarrier

Tests a bit in the specified variable, sets that bit to 0, and returns the value of the old bit as a Boolean value. Bits are tested according to the formula (0x80 >> (n & 7)) of byte ((char*)address + (n >> 3)) where n is the bit number and address is a pointer to the variable. This formula effectively breaks up the variable into 8-bit sized chunks and orders the bits in each chunk in reverse. For example, to test the lowest-order bit (bit 0) of a 32-bit integer, you would actually specify 7 for the bit number; similarly, to test the highest order bit (bit 32), you would specify 24 for the bit number.

테스트 지정된 변수의 비트 0에 해당 비트를 설정하고 부울 값으로 이전 비트의 값을 반환합니다. 비트 n은 비트 수이며, 주소는 변수에 대한 포인터 바이트의 식 (0x80에 >> (N & 7)) ((char *로) 주소 + (N >> 3))에 따라 시험한다. 이 공식은 효과적으로 8 비트 크기의 청크 및 주문 반대로 각 청크의 비트에 변수를 나눕니다. 예를 들어, 32 비트 정수의 최하위 비트 (0 비트)를 테스트하기 위해, 당신은 실제로 비트 번호 7을 지정합니다, 마찬가지로 높은 순서 비트 (32 비트)를 테스트하려면 24을 지정합니다 비트 번호입니다.

The behavior of most atomic functions should be relatively straightforward and what you would expect. Listing 4-1, however, shows the behavior of atomic test-and-set and compare-and-swap operations, which are a little more complex. The first three calls to the OSAtomicTestAndSet function demonstrate how the bit manipulation formula being used on an integer value and its results might differ from what you would expect. The last two calls show the behavior of theOSAtomicCompareAndSwap32 function. In all cases, these functions are being called in the uncontested case when no other threads are manipulating the values.

대부분의 원자 함수의 동작은 무엇을 기대 비교적 간단하고 있어야한다. 목록 4-1은, 그러나, 좀 더 복잡한 원자 테스트 ​​및 설정 비교 및 스왑 작업의 동작을 보여줍니다.OSAtomicTestAndSet 함수에 처음 세 호출은 정수 값과 그 결과에 사용되는 비트 조작 공식은 당신이 기대하는 것과 다를 수 있습니다 방법을 보여줍니다.마지막 두 호출 theOSAtomicCompareAndSwap32 함수의 동작을 보여줍니다. 모든 경우에서,이 함수는 다른 스레드가 값을 조작하지 않습니다 명백한 경우에 호출되고있다.

Listing 4-1  Performing atomic operations

int32_t  theValue = 0;
OSAtomicTestAndSet(0, &theValue);
// theValue is now 128.
 
theValue = 0;
OSAtomicTestAndSet(7, &theValue);
// theValue is now 1.
 
theValue = 0;
OSAtomicTestAndSet(15, &theValue)
// theValue is now 256.
 
OSAtomicCompareAndSwap32(256, 512, &theValue);
// theValue is now 512.
 
OSAtomicCompareAndSwap32(256, 1024, &theValue);
// theValue is still 512.

For information about atomic operations, see the atomic man page and the /usr/include/libkern/OSAtomic.h header file.

원자 작업에 대한 자세한 내용은 원자 매뉴얼 페이지와는 / usr / include와 / libkern / OSAtomic.h 헤더 파일을 참조하십시오.

Using Locks
잠금을 사용

Locks are a fundamental synchronization tool for threaded programming. Locks enable you to protect large sections of code easily so that you can ensure the correctness of that code. OS X and iOS provide basic mutex locks for all application types and the Foundation framework defines some additional variants of the mutex lock for special situations. The following sections show you how to use several of these lock types.

잠금 스레드 프로그래밍에 대한 기본적인 동기화 도구입니다. 자물쇠는 그렇게 쉽게 당신이 코드의 정확성을 보장 할 수있는 코드의 큰 부분을 보호 할 수 있습니다. OS X 및 IOS는 모든 응용 프로그램 유형에 대한 기본 뮤텍스 잠금을 제공하고 재단 프레임 워크는 특수한 상황에 대한 뮤텍스 잠금 추가적인 변형을 정의합니다.다음 섹션에서는 이러한 잠금 유형의 몇 가지를 사용하는 방법을 보여줍니다.

Using a POSIX Mutex Lock

POSIX 뮤텍스 잠금을 사용하여

POSIX mutex locks are extremely easy to use from any application. To create the mutex lock, you declare and initialize a pthread_mutex_t structure. To lock and unlock the mutex lock, you use the pthread_mutex_lock and pthread_mutex_unlock functions. Listing 4-2 shows the basic code required to initialize and use a POSIX thread mutex lock. When you are done with the lock, simply call pthread_mutex_destroy to free up the lock data structures.

POSIX 뮤텍스 잠금은 모든 응용 프로그램에서 사용하기 매우 쉽습니다.뮤텍스 잠금을 만들려면, 당신은 선언 및 pthread_mutex_t 유형 구조를 초기화합니다.뮤텍스 잠금을 잠 그거나 잠금을 해제하려면, 당신은 pthread_mutex_lock과 및 pthread_mutex_unlock은 해당 뮤텍스 함수를 사용합니다. 목록 4-2 POSIX 스레드 뮤텍스 잠금을 초기화하고 사용하는 데 필요한 기본 코드를 보여줍니다. 당신이 잠금이 완료되면, 단순히 잠금 데이터 구조를 확보하기 위해 pthread_mutex_destroy 호출합니다.

Listing 4-2  Using a mutex lock

pthread_mutex_t mutex;
void MyInitFunction()
{
    pthread_mutex_init(&mutex, NULL);
}
 
void MyLockingFunction()
{
    pthread_mutex_lock(&mutex);
    // Do work.
    pthread_mutex_unlock(&mutex);
}

Using the NSLock Class

NSLock 클래스를 사용하여

An NSLock object implements a basic mutex for Cocoa applications. The interface for all locks (including NSLock) is actually defined by the NSLocking protocol, which defines the lock and unlock methods. You use these methods to acquire and release the lock just as you would any mutex.

NSLock 객체는 코코아 응용 프로그램에 대한 기본 뮤텍스를 구현합니다. 모든 잠금 (NSLock 포함) 인터페이스는 실제로 잠금 및 잠금 해제 방법을 정의하는 NSLocking 프로토콜에 의해 정의됩니다. 당신은 잠금 당신이 어떤 뮤텍스와 마찬가지로을 획득하고 해제하려면 다음 방법을 사용합니다.

In addition to the standard locking behavior, the NSLock class adds the tryLock and lockBeforeDate: methods. The tryLock method attempts to acquire the lock but does not block if the lock is unavailable; instead, the method simply returns NO. The lockBeforeDate: method attempts to acquire the lock but unblocks the thread (and returns NO) if the lock is not acquired within the specified time limit.

방법 : 표준 잠금 동작 외에도 NSLock 클래스는 설정된 tryLock과 lockBeforeDate을 추가합니다.설정된 tryLock 메소드는 잠금을 획득하려고 시도하지 않지만 잠금을 사용할 수없는 경우 차단되지 않습니다, ​​대신 메서드는 반환하지 않습니다.lockBeforeDate : 잠금 만 차단이 해제 잠금 장치가 지정된 제한 시간 내에 획득하지 않은 경우 스레드를 (을 반환 NO) 취득 방법을 시도.

The following example shows how you could use an NSLock object to coordinate the updating of a visual display, whose data is being calculated by several threads. If the thread cannot acquire the lock immediately, it simply continues its calculations until it can acquire the lock and update the display.

다음 예는 데이터를 여러 스레드에 의해 계산되는 시각적 표시의 업데이트를 조정하는 NSLock 객체를 사용할 수있는 방법을 보여줍니다. 스레드가 즉시 잠금을 얻을 수없는 경우에 잠금을 획득하고 디스플레이를 업데이트 할 수있을 때까지, 그것은 단순히 계산을 계속합니다.

BOOL moreToDo = YES;
NSLock *theLock = [[NSLock alloc] init];
...
while (moreToDo) {
    /* Do another increment of calculation */
    /* until there’s no more to do. */
    if ([theLock tryLock]) {
        /* Update display used by all threads. */
        [theLock unlock];
    }
}

Using the @synchronized Directive

@ 동기화 지시어를 사용하여

The @synchronized directive is a convenient way to create mutex locks on the fly in Objective-C code. The @synchronized directive does what any other mutex lock would do—it prevents different threads from acquiring the same lock at the same time. In this case, however, you do not have to create the mutex or lock object directly. Instead, you simply use any Objective-C object as a lock token, as shown in the following example:

@ 동기화 지시어는 목표-C 코드에서 즉석에서 뮤텍스 잠금을 만들 수있는 편리한 방법입니다.@ 동기화 지시어는 다른 뮤텍스 잠금이 할 - 그것 것이라고한다 동시에 동일한 잠금을 획득에서 다른 스레드를 방지 할 수 있습니다. 그러나이 경우, 당신은 직접 뮤텍스 또는 잠금 개체를 만들 필요가 없습니다. 대신, 당신은 단순히 다음 예에서와 같이, 잠금 토큰으로 어떤 목표-C 객체를 사용 :

- (void)myMethod:(id)anObj
{
    @synchronized(anObj)
    {
        // Everything between the braces is protected by the @synchronized directive.
    }
}

The object passed to the @synchronized directive is a unique identifier used to distinguish the protected block. If you execute the preceding method in two different threads, passing a different object for the anObj parameter on each thread, each would take its lock and continue processing without being blocked by the other. If you pass the same object in both cases, however, one of the threads would acquire the lock first and the other would block until the first thread completed the critical section.

@ 동기화 지시문에 전달 된 개체는 보호 블록을 구분하는 데 사용되는 고유 식별자입니다. 당신이 각 스레드에 anObj 매개 변수에 다른 객체를 전달, 두 개의 서로 다른 스레드 위의 방법을 실행하면, 각각은 잠금을 가지고 다른에 의해 차단되지 않고 처리를 계속합니다. 당신은 두 경우 모두에 동일한 개체를 전달하는 경우, 그러나, 스레드 중 하나는 먼저 잠금을 획득 것이며, 첫 번째 스레드가 중요 섹션을 완료 할 때까지 다른 차단됩니다.

As a precautionary measure, the @synchronized block implicitly adds an exception handler to the protected code. This handler automatically releases the mutex in the event that an exception is thrown. This means that in order to use the @synchronized directive, you must also enable Objective-C exception handling in your code. If you do not want the additional overhead caused by the implicit exception handler, you should consider using the lock classes.

예방 조치로, @ 동기화 블록은 암시 적으로 보호 된 코드에 예외 처리기를 추가합니다. 이 핸들러는 자동으로 예외가 발생하는 경우에 뮤텍스를 해제합니다. 이 @ 동기화 지시어를 사용하려면, 당신은 또한 당신의 코드에서 오브젝티브-C 예외 처리를 사용하도록 설정해야합니다 것을 의미합니다. 당신은 암시 적 예외 처리기에 의해 발생하는 추가 오버 헤드를 원하지 않는 경우, 잠금 클래스를 사용하는 것이 좋습니다.

For more information about the @synchronized directive, see The Objective-C Programming Language.
@ 동기화 지시문에 대한 자세한 내용은, 오브젝티브-C 프로그래밍 언어를 참조하십시오.

Using Other Cocoa Locks

기타 코코아 잠금을 사용

The following sections describe the process for using several other types of Cocoa locks.
다음 섹션에서는 코코아 잠금의 몇 가지 다른 유형을 사용하는 프로세스를 설명합니다.

Using an NSRecursiveLock Object

NSRecursiveLock 개체를 사용하여

The NSRecursiveLock class defines a lock that can be acquired multiple times by the same thread without causing the thread to deadlock. A recursive lock keeps track of how many times it was successfully acquired. Each successful acquisition of the lock must be balanced by a corresponding call to unlock the lock. Only when all of the lock and unlock calls are balanced is the lock actually released so that other threads can acquire it.

NSRecursiveLock 클래스는 교착 상태 스레드를 유발하지 않고 동일한 스레드에서 여러 번 획득 할 수있는 잠금을 정의합니다.재귀 잠금이 성공적으로 획득 한 횟수를 추적합니다.잠금 각각의 성공적인 인수는 잠금을 해제하기 해당 호출에 의해 균형을해야합니다.잠금 및 잠금 해제 호출이 모두 균형 된 경우에만 실제로 다른 스레드가 그것을 취득 할 수 있도록 출시 된 자물쇠입니다.

As its name implies, this type of lock is commonly used inside a recursive function to prevent the recursion from blocking the thread. You could similarly use it in the non-recursive case to call functions whose semantics demand that they also take the lock. Here’s an example of a simple recursive function that acquires the lock through recursion. If you did not use an NSRecursiveLock object for this code, the thread would deadlock when the function was called again.

이름에서 알 수 있듯이, 이러한 유형의 잠금은 일반적으로 스레드를 차단에서 재귀를 방지하기 위해 재귀 함수 내에서 사용됩니다. 당신은 마찬가지로 그 의미 그들은 또한 잠금을 것을 요구 함수를 호출하는 비 - 재귀 경우에 사용할 수 있습니다. 여기에서 재귀를 통해 잠금을 획득하는 간단한 재귀 함수의 예입니다. 이 코드 NSRecursiveLock 개체를 사용하지 않은 경우, 스레드는 함수가 다시 호출 될 때 교착 상태가됩니다.

NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
 
void MyRecursiveFunction(int value)
{
    [theLock lock];
    if (value != 0)
    {
        --value;
        MyRecursiveFunction(value);
    }
    [theLock unlock];
}
 
MyRecursiveFunction(5);

Using an NSConditionLock Object
NSConditionLock 개체를 사용하여

An NSConditionLock object defines a mutex lock that can be locked and unlocked with specific values. You should not confuse this type of lock with a condition (see “Conditions”). The behavior is somewhat similar to conditions, but is implemented very differently.

NSConditionLock 객체는 잠겨 특정 값으로 잠금을 해제 할 수 있습니다 뮤텍스 잠금을 정의합니다. 당신은 조건 ( "조건"참조) 이러한 유형의 잠금을 혼동하지 않아야합니다.동작 조건이 비슷하지만, 매우 다르게 구현됩니다.

Typically, you use an NSConditionLock object when threads need to perform tasks in a specific order, such as when one thread produces data that another consumes. While the producer is executing, the consumer acquires the lock using a condition that is specific to your program. (The condition itself is just an integer value that you define.) When the producer finishes, it unlocks the lock and sets the lock condition to the appropriate integer value to wake the consumer thread, which then proceeds to process the data.

스레드가 같은 하나의 스레드가 다른 스레드가 소비하는 데이터를 생성 할 때와 같이 특정 순서로 작업을 수행해야하는 경우 일반적으로, 당신은 NSConditionLock 개체를 사용합니다. 생산자가 실행되는 동안, 소비자는 프로그램에 특정한 조건을 사용하여 잠금을 획득합니다. (조건 자체가 정의하는 단지 정수 값입니다.) 생산자가 완료되면 잠금을 해제하고 데이터를 처리하기 위해 진행 소비자 스레드를 깨워 해당 정수 값으로 잠금 상태를 설정합니다.

The locking and unlocking methods that NSConditionLock objects respond to can be used in any combination. For example, you can pair a lock message withunlockWithCondition:, or a lockWhenCondition: message with unlock. Of course, this latter combination unlocks the lock but might not release any threads waiting on a specific condition value.

NSConditionLock 개체에 대응하는 잠금 및 잠금 해제 방법을 조합하여 사용할 수 있습니다. 또는 lockWhenCondition : 잠금 해제와 메시지 예를 들어, 잠금 메시지 withunlockWithCondition를 페어링 할 수 있습니다. 물론, 후자의 조합은 잠금을 해제하지만, 특정 조건 값에서 대기하는 스레드를 해제하지 않을 수 있습니다.

The following example shows how the producer-consumer problem might be handled using condition locks. Imagine that an application contains a queue of data. A producer thread adds data to the queue, and consumer threads extract data from the queue. The producer need not wait for a specific condition, but it must wait for the lock to be available so it can safely add data to the queue.

다음 예는 생산자 - 소비자 문제는 조건 잠금을 사용하여 처리하는 방법을 보여줍니다.응용 프로그램이 데이터를 큐에 포함되어 있는지 상상해보십시오.생산자 스레드는 큐에 데이터를 추가, 소비자 스레드는 큐에서 데이터를 추출합니다.프로듀서는 특정 조건을 기다릴 필요가 없습니다,​​하지만 안전하게 큐에 데이터를 추가 할 수 있도록 그것을 사용할 수 있도록 잠금을 기다려야합니다.

id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
 
while(true)
{
    [condLock lock];
    /* Add data to the queue. */
    [condLock unlockWithCondition:HAS_DATA];
}

Because the initial condition of the lock is set to NO_DATA, the producer thread should have no trouble acquiring the lock initially. It fills the queue with data and sets the condition to HAS_DATA. During subsequent iterations, the producer thread can add new data as it arrives, regardless of whether the queue is empty or still has some data. The only time it blocks is when a consumer thread is extracting data from the queue.

잠금 장치의 초기 상태가 NO_DATA로 설정되어 있기 때문에, 생산자 스레드는 처음에 잠금을 획득 아무 문제가 없어야합니다. 그것은 데이터 큐를 채우고 HAS_DATA에 조건을 설정합니다. 이후 반복하는 동안, 생산자 스레드는 도착하는대로 관계없이 큐가 비어 있는지의 새로운 데이터를 추가하거나 여전히 데이터가 있습니다.소비자 스레드는 큐에서 데이터를 추출 할 때 그것을 차단하는 유일한 시간이다.

Because the consumer thread must have data to process, it waits on the queue using a specific condition. When the producer puts data on the queue, the consumer thread wakes up and acquires its lock. It can then extract some data from the queue and update the queue status. The following example shows the basic structure of the consumer thread’s processing loop.

소비자 스레드 프로세스에 데이터가 있어야하기 때문에 특정 조건을 사용하여 큐에 대기합니다. 생산자가 큐에 데이터를 넣으면, 소비자 스레드가 깨어 나면 그 잠금을 획득합니다. 그런 다음 대기열에서 일부 데이터를 추출하여 대기열 상태를 업데이트 할 수 있습니다.다음 예제에서는 소비자 스레드의 처리 루프의 기본 구조를 보여줍니다.

while (true)
{
    [condLock lockWhenCondition:HAS_DATA];
    /* Remove data from the queue. */
    [condLock unlockWithCondition:(isEmpty ? NO_DATA : HAS_DATA)];
 
    // Process the data locally.
}

Using an NSDistributedLock Object
NSDistributedLock 개체를 사용하여

The NSDistributedLock class can be used by multiple applications on multiple hosts to restrict access to some shared resource, such as a file. The lock itself is effectively a mutex lock that is implemented using a file-system item, such as a file or directory. For an NSDistributedLock object to be usable, the lock must be writable by all applications that use it. This usually means putting it on a file system that is accessible to all of the computers that are running the application.

NSDistributedLock 클래스는 파일과 같은 일부 공유 리소스에 대한 액세스를 제한하는 여러 호스트에서 여러 응용 프로그램에서 사용할 수 있습니다.잠금 자체는 효과적으로 파일이나 디렉토리로 파일 시스템 항목을 사용하여 구현됩니다 뮤텍스 잠금입니다.NSDistributedLock 객체를 사용할 수있는 경우, 잠금을 사용하는 모든 응용 프로그램에 쓰기 권한이 있어야합니다. 이것은 일반적으로 응용 프로그램을 실행하는 모든 컴퓨터에 액세스 할 수있는 파일 시스템에 넣고 의미합니다.

Unlike other types of lock, NSDistributedLock does not conform to the NSLocking protocol and thus does not have a lock method. A lock method would block the execution of the thread and require the system to poll the lock at a predetermined rate. Rather than impose this penalty on your code, NSDistributedLockprovides a tryLock method and lets you decide whether or not to poll.

자물쇠의 다른 종류와는 달리, NSDistributedLock는 NSLocking 프로토콜을 준수하지 않는 및 따라서 잠금 방법이 없습니다.Lock 메서드는 스레드의 실행을 차단하고 시스템이 미리 정해진 속도로 잠금 장치를 폴링 할 필요합니다. 코드에서이 벌금을 부과하는 대신, 설정된 tryLock 메소드를 NSDistributedLockprovides하고 있는지 여부 여론 조사로 결정할 수 있습니다.

Because it is implemented using the file system, an NSDistributedLock object is not released unless the owner explicitly releases it. If your application crashes while holding a distributed lock, other clients will be unable to access the protected resource. In this situation, you can use the breakLock method to break the existing lock so that you can acquire it. Breaking locks should generally be avoided, though, unless you are certain the owning process died and cannot release the lock.

이 파일 시스템을 사용하여 구현되기 때문에 소유자가 명시 적으로 해제하지 않는 한, NSDistributedLock 개체가 해제되지 않습니다. 응용 프로그램 충돌이 분산 락을 잡고 있으면, 다른 클라이언트가 보호 된 리소스에 액세스 할 수 없습니다. 이 상황에서, 당신은 당신이 그것을 얻을 수 있도록 기존의 잠금을 깰 수있는 breakLock 메서드를 사용할 수 있습니다. 당신이 소유하는 프로세스가 죽었을 확신하고 잠금을 해제 할 수 없다면 파괴 잠금은 일반적으로하지만, 피해야한다.

As with other types of locks, when you are done using an NSDistributedLock object, you release it by calling the unlock method.

자물쇠의 다른 종류와 마찬가지로, 당신은 NSDistributedLock 객체를 사용하여 수행하는 경우, 당신은 잠금 해제 메서드를 호출하여 놓습니다.

Using Conditions
조건을 사용하여

Conditions are a special type of lock that you can use to synchronize the order in which operations must proceed. They differ from mutex locks in a subtle way. A thread waiting on a condition remains blocked until that condition is signaled explicitly by another thread.

상태는 작업을 진행해야하는 순서를 동기화하는 데 사용할 수있는 잠금의 특별한 유형입니다. 그들은 미묘한 방식으로 뮤텍스 잠금 다릅니다. 해당 조건이 다른 스레드에 의해 명시 적으로 신호 할 때까지 상태를 기다리는 스레드가 차단 된 상태로 유지됩니다.

Due to the subtleties involved in implementing operating systems, condition locks are permitted to return with spurious success even if they were not actually signaled by your code. To avoid problems caused by these spurious signals, you should always use a predicate in conjunction with your condition lock. The predicate is a more concrete way of determining whether it is safe for your thread to proceed. The condition simply keeps your thread asleep until the predicate can be set by the signaling thread.

운영 체제를 실행에 관련된 미묘한 차이로 인해 상태 잠금은 그들이 실제로 코드 신호를하지 않은 경우에도 의사 성공을 반환 할 수 있습니다. 이러한 스퓨리어스 신호에 의해 발생하는 문제를 방지하기 위해, 당신은 항상 당신의 상태 잠금 장치와 함께 술어를 사용합니다.조건은 스레드가 계속하는 것이 안전한지 여부를 결정하는보다 구체적인 방법입니다.술어가 신호를 스레드에 의해 설정 될 때까지 상태는 단순히 잠의 스레드를 유지합니다.

The following sections show you how to use conditions in your code.
다음 섹션에서는 코드에서 조건을 사용하는 방법을 보여줍니다.

Using the NSCondition Class

NSCondition 클래스를 사용하여

The NSCondition class provides the same semantics as POSIX conditions, but wraps both the required lock and condition data structures in a single object. The result is an object that you can lock like a mutex and then wait on like a condition.

NSCondition 클래스는 POSIX 조건과 같은 의미를 제공하지만 단일 개체에 필요한 잠금 및 상태 데이터 구조를 모두 래핑합니다.결과는 뮤텍스와 같이 잠그고 다음 조건처럼에서 대기 할 수있는 개체입니다.

Listing 4-3 shows a code snippet demonstrating the sequence of events for waiting on an NSCondition object. The cocoaCondition variable contains anNSCondition object and the timeToDoWork variable is an integer that is incremented from another thread immediately prior to signaling the condition.

목록 4-3 NSCondition 개체에서 대기를위한 이벤트의 순서를 설명하는 코드를 보여줍니다.cocoaCondition 변수는 anNSCondition 개체를 포함하고 timeToDoWork 변수는 직전 상태를 신호하는 또 다른 스레드에서 증가되는 정수입니다.

Listing 4-3  Using a Cocoa condition

[cocoaCondition lock];
while (timeToDoWork <= 0)
    [cocoaCondition wait];
 
timeToDoWork--;
 
// Do real work here.
 
[cocoaCondition unlock];

Listing 4-4 shows the code used to signal the Cocoa condition and increment the predicate variable. You should always lock the condition before signaling it.

목록 4-4 코코아 조건을 신호와 조건 변수를 증가하는 데 사용되는 코드를 보여줍니다. 당신은 항상 신호 전에 상태를 잠 가야합니다.

Listing 4-4  Signaling a Cocoa condition

[cocoaCondition lock];
timeToDoWork++;
[cocoaCondition signal];
[cocoaCondition unlock];

Using POSIX Conditions

POSIX 조건 사용

POSIX thread condition locks require the use of both a condition data structure and a mutex. Although the two lock structures are separate, the mutex lock is intimately tied to the condition structure at runtime. Threads waiting on a signal should always use the same mutex lock and condition structures together. Changing the pairing can cause errors.

POSIX 스레드 상태 잠금 상태 데이터 구조와 뮤텍스 모두의 사용을 필요로합니다.두 개의 잠금 구조는 분리되어 있지만, 뮤텍스 잠금이 밀접하게 런타임 상태 구조에 연결되어 있습니다.신호 대기하는 스레드는 항상 함께 동일한 뮤텍스 잠금 상태 구조를 사용해야합니다.페어링을 변경하면 오류가 발생할 수 있습니다.

Listing 4-5 shows the basic initialization and usage of a condition and predicate. After initializing both the condition and the mutex lock, the waiting thread enters a while loop using the ready_to_go variable as its predicate. Only when the predicate is set and the condition subsequently signaled does the waiting thread wake up and start doing its work.

목록 4-5 조건과 조건의 기본 초기화 및 사용법을 보여줍니다.상태와 뮤텍스 잠금을 모두 초기화 한 후 대기중인 스레드는 조건으로 ready_to_go 변수를 사용하여 while 루프를 입력합니다.조건을 설정하고 조건이 연속적으로 신호를 경우에만 대기중인 스레드가 일어나 그 일을 시작 않습니다.

Listing 4-5  Using a POSIX condition

pthread_mutex_t mutex;
pthread_cond_t condition;
Boolean     ready_to_go = true;
 
void MyCondInitFunction()
{
    pthread_mutex_init(&mutex);
    pthread_cond_init(&condition, NULL);
}
 
void MyWaitOnConditionFunction()
{
    // Lock the mutex.
    pthread_mutex_lock(&mutex);
 
    // If the predicate is already set, then the while loop is bypassed;
    // otherwise, the thread sleeps until the predicate is set.
    while(ready_to_go == false)
    {
        pthread_cond_wait(&condition, &mutex);
    }
 
    // Do work. (The mutex should stay locked.)
 
    // Reset the predicate and release the mutex.
    ready_to_go = false;
    pthread_mutex_unlock(&mutex);
}

The signaling thread is responsible both for setting the predicate and for sending the signal to the condition lock. Listing 4-6 shows the code for implementing this behavior. In this example, the condition is signaled inside of the mutex to prevent race conditions from occurring between the threads waiting on the condition.

신호 스레드는 조건을 설정하고 조건 잠금 장치에 신호를 보내는 모두 책임이 있습니다. 목록 4-6이 동작을 구현하는 코드를 보여줍니다. 이 예에서, 조건은 조건에 대기 스레드간에 발생하는 경쟁 조건을 방지하기 위해 뮤텍스의 내부 신호를.

Listing 4-6  Signaling a condition lock

void SignalThreadUsingCondition()
{
    // At this point, there should be work for the other thread to do.
    pthread_mutex_lock(&mutex);
    ready_to_go = true;
 
    // Signal the other thread to begin work.
    pthread_cond_signal(&condition);
 
    pthread_mutex_unlock(&mutex);
}

Posted by 창업자닉군
,