Android Document  SDK old PDF 파일
Android SMP(6/7) - 사례:해야 할 것
작성자
작성일 2011-05-02 (월) 21:22
ㆍ추천: 0  ㆍ조회: 8510      
IP: 121.xxx.76

 
 
 
목차
 
1. 도입
2. 이론
   2.1. 메모리 일관성 모델(Memory Consistency Models)
   2.2. 데이터 메모리 장벽(Data Memory Barriers)
   2.3. 원자적 오퍼레이션들(Atomic Operations)
3. 사례
   3.1. C에서 하지 말 것
   3.2. Java에서 하지 말 것.
   3.3. 해야 할 것
4. 부록
 
 
 
3.3 해야 할 (What To Do)
 

3.3.1 일반적 조언(General Advice)

 
C/C++에서, mutex와 semaphore와 같은 pthread 오퍼레이션을 사용하라. 이것들은 모든 안드로이드
플랫폼에서 올바르고 효율적으로 작동하는 제대로 된 메모리 장벽을 포함하고 있다. 예를 들어 mutex을
보유하지 않고 condition variable 신호를 보내는 것을 피해야 하는 것처럼 그것들을 올바르게 사용하라.
 
안드로이드 atomic 함수들을 직접적으로 사용하는 것을 피하는 것이 최선이다. pthread mutex를 lock하고
unlock하는 것은 각각에 대한 경합이 없다면 단일 원자적 오퍼레이션을 요구한다. 그러므로 여러분은
원자적 오퍼레이션을 가지고 mutex 호출을 대체함으로써 많은 것을 절약하지는 못할 것이다. 만약
여러분이 lock-free 디자인이 필요하다면, 시작하기 전에 이 문서 전체의 개념을 완전히 이해해야 한다.
(또는, 더 좋은 것은, SMP ARM에서 올바르게 되는 것으로 알려진 기존의 라이브러리를 찾아라.)
 
C/C++ 에서 volatile을 사용하는 것을 극도로 신중해야 한다. 그것은 종종 일어날 것을 동시에 기다리는
문제를 보인다.
 
Java에서 최고의 답은 일반적으로 java.util.concurrent 패키지의 적절한 유틸리티 클래스를 사용하는
것이다. 그 코드는 잘 작성되었고, SMP에서 잘 테스트되었다.
 
아마도 여러분이 할 수 있는 가장 안전한 것은 여러분의 클래스를 불변immutable하게 만드는 것이다.
String이나 Integer와 같은 클래스의 오브젝트는 모든 동기화 이슈를 회피하도록 한번 클래스가 생성되면
변경될 수 없는 데이터를 보유한다. The book Effective Java, 2nd. Ed은 “Item 15: Minimize Mutability”에
상세한 명령어들을 포함하고 있다. (특별히 필드를 final로 선언하는 것의 중요성에 주목하라.)
 
만약 이러한 설정들이 전혀 보이지 않는다면, 하나 이상의 쓰레드 의해서 접근될 수 있는 임의의 필드를
보호하기 위해 Java “synchronized” 구문이 사용되어야 한다. 만약 여러분의 상황에 대해 mutex를
동작할 수 없다면, 여러분은 공유 필드를 “volatile”로 선언해야 한다. 그러나 여러분은 쓰레드들 간의
상호작용을 이해하는데 매우 조심해야 한다. volatile 선언이 여러분을 일반적 병렬 프로그래밍 실수에서
보호하지는 않는다. 하지만 그것은 최적화 컴파일러와 SMP 오류와 관련된 알 수 없는 실패를 여러분이
피하도록 돕는다.
 
Java 메모리 모델은 일단 생성자가 끝나면 모든 쓰레드에서 보이는 final 필드에 대한 할당을 보장한다 
- 이것은 불변 클래스immutable classes의 필드에 올바른 동기화를 가능하게끔 한다. 만약 부분적으로
생성된 오브젝트가 다른 쓰레드에게 보이도록 허용된다면 이 보장은 이루어지지 않는다. 안전한 생성
사례를 따르는 것이 필수적이다.
 

3.3.2 동기화 원형 보장(Synchronization Primitive Guarantees)

 
pthread 라이브러리와 VM은 한 쌍의 유용한 보장을 만든다: 신규 쓰레드를 생성한 쓰레드에 의해 이전에
수행된 모든 접근들은 신규 쓰레드가 시작하자 마자 그 쓰레드에 의해 관측 가능할 것이다. 그리고 종료되는
쓰레드에 의해 수행되는 모든 접근은 그 쓰레드에 대한 join()이 리턴할 때 관측 가능할 것이다. 이것은
여러분이 신규 쓰레드를 위한 데이터를 준비할 때나 또는 join된 쓰레드의 결과를 검사할 때 추가적인
동기화가 필요하지 않다는 것을 의미한다.
 
이러한 보장들이 풀pool을 형성하고 있는 쓰레드들과의 상호작용에 적용되는지 여부는 쓰레드 풀pool
구현에 의존한다.
 
C/C++에서, pthread 라이브러리는 임의의 쓰레드가 mutex를 unlock 하기 전에 만든 임의의 접근은 다른
쓰레드가 동일한 mutex를 lock 한 후에 관측할 것을 보장한다. 그것은 또한 condition variable 에
signal() 또는 broadcast() 를 호출하기 전에 만들어진 임의의 접근이 깨어난 쓰레드에 의해 관측될
것이라는 것도 보장한다.
 
Java 언어 쓰레드와 monitor는 비슷한 오퍼레이션에 대한 유사한 보장을 만든다.

 
3.3.3 C/C++ 있을 변화들(Upcoming Changes to C/C++)

 
C와 C++ 언어 표준은 현명한 원자적 오퍼레이션 집합을 포함하도록 진화하고 있다. 보편적인 데이터
타입에 대해 선택 가능한 메모리 장벽 구문(relaxed, consume, acquire, release, acq_rel, seq_cst)을
갖는 전체full matrix 호출이 정의된다.
 
이 명세서에 대한 조언을 얻고자 한다면 더 읽기 섹션을 보라.

 
3.3.4 마무리 노트(Closing Notes)

 
이 문서는 그저 표면을 묘사하는 것 이상이지만, 얕은 홈 이상을 취급하지는 않는다. 이것은 매우 넓고
깊은 주제이다. 더 설명할 약간의 영역이 있다.

  • Happens-before, synchronizes-with, 그리고 Java 메모리 모델의 다른 필수 개념을 배워라.
    (이것을 알지 않고 “volatile”이 실제로 의미하는 것을 이해하는 것은 어렵다.)
  • 컴파일러가 코드를 재정렬할 때 허용되는 것과 아닌 것을 찾아봐라.
    (JSR-133 스펙은 기대하지 않았던 결과를 초래하는 합법적 변환에 대한 약간의 엄청난 예제를
    가지고 있다.)
  • Java와 C++에서 불변의 클래스를 작성하는 방법을 찾아라.
    (생성 이후에 단지 어떤 것도 변경하지 않는다는 것 이상의 것들이 이곳에 있다.)
  • Effective Java, 2nd Ed.의 병렬 섹션에서 권장사항을 자기 것으로 만들어라.
    (예를 들어, 여러분은 synchronized 블록 안에서 overridden 되는 메쏘드 호출을 피해야 한다.)
  • x86과 ARM에서 여러분이 사용할 수 있는 메모리 장벽의 종류가 무엇이 있는지 이해하라.
    (그리고 그것들에 대한 다른 CPU들도, 예를 들어, Itanium의 acquire/release 명령어 수정들.)
  • 무엇을 사용할 수 있는 지 알기 위해, java.util.concurrent 와 java.util.concurrent.atomic API들을 읽어라. (net.jcip.anntations 에서) @ThreadSafe와 @GuardedBy와 같은 병렬 표기를 사용하는 것을 상기하라.
부록에 있는 더 읽기 섹션은 이러한 주제를 더 잘 묘사하는 문서와 웹 사이트를 링크한다.

계속 : 

덧글 쓰기 0
3500
※ 회원등급 레벨 0 이상 읽기가 가능한 게시판입니다.