CAS lock-free

12231 단어 Lock
등급:http://www.cnblogs.com/lucifer1982/archive/2009/04/08/1431992.html
http://en.wikipedia.org/wiki/Compare-and-swap
In  computer science , compare-and-swap (CAS) is an  atomic   instruction  used in  multithreading  to achieve  synchronization . It compares the contents of a memory location to a given value and, only if they are the same, modifies the contents of that memory location to a given new value. This is done as a single atomic operation. The atomicity guarantees that the new value is calculated based on up-to-date information; if the value had been updated by another thread in the meantime, the write would fail. The result of the operation must indicate whether it performed the substitution; this can be done either with a simple  Boolean  response (this variant is often called compare-and-set), or by returning the value read from the memory location (not the value written to it).
The following C function shows the basic behavior of a compare-and-swap variant that returns the old value of the specified memory location; however, this version does not provide the crucial guarantees of atomicity that a real compare-and-swap operation would:
int compare_and_swap (int* reg, int oldval, int newval) 

{

  int old_reg_val = *reg;

  if (old_reg_val == oldval) 

     *reg = newval;

  return old_reg_val;

}


lock-free  프로 그래 밍 은 정말 사람 을 사랑 하고 미워 하 게 한다.블 로 거들 은 이전에 lock-free 프로 그래 밍 에 관 한 글 을 몇 편 쓴 적 이 있다.예 를 들 어잠 금 없 는 프로 그래 밍 에 대하 여,병발 데이터 구조:매혹 적 인 원자.lock-free 프로 그래 밍 을 더욱 깊이 이해 하고 실천 하려 면CLR 2.0 Memory Model,병렬 데이터 구조:Stack를 참고 하 십시오.이 글 은 lock-free 기술 을 어떻게 사용 하 는 지 계속 논술 하지 않 고 부정적인 영향 에 대해 이야기 할 계획 이다.lock-free 에 대한 전면적 인 인식 을 갖 게 합 니 다.
lock-free 프로 그래 밍 하면 현실 적 으로 CAS 원 어 를 자주 사용 합 니 다.CAS 는 영어 Compare and Swap 의 약자 입 니 다.Windows 와.NET 플랫폼 에 서 는 역사적 인 이유 로 Interlocked API 로 쓰 여 있 습 니 다.원자 조작 이 x86 구조 CPU 에 대응 하 는 어 셈 블 리 명령 은 XCHG,CMPXHG,INC 등 이 있 습 니 다.물론 LOCK 를 접두사 로 추가 해 야 합 니 다.  병발 데이터 구조:매혹 적 인 원자 )。
CAS 원 어 는 경도 와 중도 경쟁 에서 프로그램 성능 을 크게 향상 시 킬 수 있 는 것 은 사실이다.그러나 모든 일 에 유리 하면 반드시 폐단 이 있다.CAS 원 어 는 프로그램의 신축성 을 극도로 말살 했다(기타 단점 은잠 금 없 는 프로 그래 밍 에 대하 여를 보십시오).관리 들 은 이런 관점 이 좀 과격 하 다 고 생각 할 지 모 르 지만 사실은 그렇다.블 로 거들 이 자세히 말 하도록 허락 해 주 십시오.
  • CAS 의 원자 성 은 하드웨어 실현 에 달 려 있다.대부분의 Intel 과 AMD 의 CPU 는 캐 시 를 관리 하기 위해 MOSEI 캐 시 일치 성 프로 토 콜 을 사용 합 니 다.이 구조 에서 프로세서 캐 시 내 CAS 작업 은 상대 적 으로 비용 이 저렴 하 다.그러나 자원 경쟁 이 일어나 면 캐 시 실효 와 버스 점용 이 발생 한다.캐 시가 효력 을 잃 을 수록 버스 가 점용 되 고 CAS 작업 이 지연 된다.캐 시 경쟁 용 은 프로그램 신축성 킬러 입 니 다.물론 비 CAS 메모리 조작 에 도 마찬가지 지만 CAS 상황 은 더욱 찰떡 이다.
  • CAS 작업 은 일반 메모리 작업 보다 더 많은 CPU 주 기 를 소비 합 니 다.이것 은 캐 시 등급 의 추가 부담,쓰기 버퍼 리 셋 과 메모리 울 타 리 를 통과 하 는 제한 과 수요,컴 파일 러 가 CAS 작업 에 최적화 하 는 능력 덕분이다.
  • CAS 는 병행 작업 을 최적화 하 는 데 자주 사용 된다.이것 은 CAS 작업 이 실패 하면 일부 명령 을 다시 시도 하 게 된다 는 것 을 의미한다.(전형 적 인 스크롤 백 작업)아무 소 용이 없 더 라 도 그것 은 헛 된 일 을 할 것 이다.성공 하 든 실패 하 든 경쟁 용 위험 이 증가 합 니 다.

  • 대부분의 CAS 작업 은 잠 금 이 들 어 오고 종료 할 때 발생 합 니 다.잠 금 은 단일 CAS 작업 으로 구 축 될 수 있 지만.NET CLR Monitor 류 는 두 개(하 나 는 Enter 방법,다른 하 나 는 Exit 방법)를 사용 했다.lock-free 알고리즘 도 잠 금 메커니즘 대신 CAS 원 어 를 자주 사용한다.그러나 메모리 재 구성 으로 인해 이러한 알고리즘 은 CAS 명령 을 사용 하 더 라 도 명시 적 인 울타리 가 필요 하 다.자물쇠 메커니즘 은 매우 사악 하지만,대부분의 합격 한 개발 자 들 은 자 물 쇠 를 최대한 적 게 가지 도록 하 는 것 을 안다.따라서 잠 금 메커니즘 이 얄 밉 고 성능 에 도 영향 을 미친다.그러나 대량의 빈번 한 CAS 조작 에 비해 프로그램의 신축성 에 영향 을 주지 않 는 다.
    간단 한 예 를 들 어 100,000,000 회 를 늘 렸 다.이렇게 하려 면 몇 가지 방법 이 있다.단일 핵 단일 프로세서 에서 만 실행 된다 면 일반적인 메모리 작업 을 사용 할 수 있 습 니 다.
    static volatile int counter = 0;
    
    static void BaselineCounter()
    
    {
    
        for (int i = 0; i < Count; i++)
    
        {
    
            counter++;
    
        }
    
    }

     
    상기 코드 예제 가 스 레 드 가 안전 한 것 은 아니 지만 카운터 에 좋 은 시간 기준 을 제공 한 것 은 분명 하 다.다음은 스 레 드 안전 의 첫 번 째 방법 으로 LOCK INC 를 사용 합 니 다.
     
    static volatile int counter = 0;
    
    static void LockIncCounter()
    
    {
    
        for (int i = 0; i < Count; i++)
    
        {
    
            Interlocked.Increment(ref counter);
    
        }
    
    }

    현재 코드 예제 스 레 드 가 안전 합 니 다.우 리 는 또 다른 방식 을 채택 하여 노선 의 안전 을 보장 할 수 있다.만약 검증(예 를 들 어 메모리 넘 침 보호)을 실행 해 야 한다 면,우 리 는 보통 이런 방식 을 사용 할 것 이다.CMPXCHG(즉 CAS)를 사용 하 는 것 입 니 다.
    static volatile int counter = 0;
    
    static void CASCounter()
    
    {
    
        for (int i = 0; i < Count; i++)
    
        {
    
            int oldValue;
    
            do
    
            {
    
                oldValue = counter;
    
            }
    
            while (Interlocked.CompareExchange(ref counter, oldValue + 1, oldValue) != oldValue);
    
        }
    
    }

    지금 재 미 있 는 질문 을 하 겠 습 니 다.캐 시 경쟁 을 할 때 어떤 방법 이 더 느 립 니까?깜짝 놀 랄 수도 있어.
    Intel 4 핵 프로세서 에서 테스트 결 과 는 다음 과 같 습 니 다.
    F1
    그림 에서 CPU 가 2 개의 핵 을 사용 할 때 BaselineCounter 방법 은 단일 핵 단일 상황 의 2.11 배 이다.다른 상황 은 유사 하 다.결과 비 교 를 통 해 우 리 는 더 많은 병발 성 이 결 과 를 더욱 어 묵 으로 만 들 었 다 는 것 을 알 수 있다.이것 은 대부분의 원인 이 메모리 경쟁 으로 인 한 것 이다.
    CAS 작업 이 실 패 했 을 때 회전 대기 로 CASCounter 방법의 다 중 핵 처리 장치 에서 의 성능 을 개선 할 수 있 습 니 다(구체 적 인 기 교 는 여름 이 좋 은 계절 형의스스로 경량급 의 신 호 량 을 실현 하 다(1)|(2)).이 는 자물쇠 와 관련 된 내 연 이 자 물 쇠 를 방해 하 는 데 걸 리 는 시간 을 크게 줄 일 수 있다.
    물론 이 예 는 극단 적 이다.그것 은 같은 메모리 주 소 를 자주 반복 해서 수정한다.기간 동안 특정한 함수 호출 을 삽입 하면 공유 메모리 에 접근 을 지연 시 키 면 스트레스 를 크게 완화 할 수 있 습 니 다.
    예 를 들 어 두 개의 함수 호출 을 삽입 하면 우 리 는 다음 과 같은 데 이 터 를 얻 을 수 있 습 니 다.
    F264 개의 함수 호출 을 삽입 한 후 데 이 터 는 다음 과 같 습 니 다.
    F3이때 우 리 는 다 핵 이 단 핵 보다 적은 시간 을 보 았 다.이것 이 바로 우리 가 병행 을 사용 하 는 데 가 져 온 가속 이다.여기 서 우 리 는 2 개 에서 64 개 함수 호출 로 결과 가 점점 좋아 졌 으 니 64 개 함수 호출 이 더 좋아 지지 않 을 까 생각 할 수 있 습 니 다.실제로 128 개의 함수 호출 을 삽입 한 후 가속 이 한계 에 이 르 렀 다.결 과 는 다음 과 같다.
    F4가속 비 를 어떻게 계산 하 는 지 참고병행 사고[II].
    세상 에 공 짜 는 없다.CAS 도 예 외 는 아니다.우 리 는 lock-free CAS 코드 를 코드 에 신중하게 넣 어야 하 며,스 레 드 가 자주 실행 되 는 지 알 아야 합 니 다.우 리 는 공유 가 악마 라 는 것 을 다음 과 같은 말로 요약 할 수 있다.그것 은 근본적으로 응용 프로그램의 신축성 을 제한 하 므 로 가능 한 한 피 하 는 것 이 가장 좋다.공유 메모 리 는 병행 제어 가 필요 하고,병행 제 어 는 CAS 가 필요 하 다.CAS 는 또 매우 비 싸 공유 메모리 도 매우 비싸다.많은 사람들 이 lock-free 기술,사무 메모리,읽 기와 쓰기 자물쇠 등 프로그램 신축성 을 개선 할 수 있다 고 주장 한다.안 타 깝 게 도 이런 경 우 는 드물다.CAS 는 종종 잠 금 메커니즘 을 정확하게 실현 하 는 해결 방안 보다 더 나쁘다.공유 메모리,낙관적 실패 시도,캐 시 실효 등 이 큰 원인 이다.
    Update 는 2009 년 4 월 8 일 21:10
    overred  형 은 review 라 는 글 에서 좋 은 질문 을 했 습 니 다.Interlocked API 를 사용 할 때 공유 변 수 는 volatile 로 수식 하지 않 습 니 다.
    이 문 제 를 더욱 편리 하 게 설명 하기 위해 서 나 는 간단 한 코드 예 시 를 써 서 다음 과 같다.
    using System;
    
    
    
    namespace Lucifer.CSharp.Sample
    
    {
    
        class Program
    
        {
    
            static volatile int x;
    
    
    
            static void Main(string[] args)
    
            {
    
                Foo(ref x);
    
            }
    
    
    
            static void Foo(ref int y)
    
            {
    
                while (y == 0) ;
    
            }
    
        }
    
    }

     
    우리 가 Visual Studio 에서 이 코드 를 컴 파일 할 때 IDE 는 컴 파일 경 고 를 보 냅 니 다.다음 과 같 습 니 다.
    F5일반적으로 우 리 는 이러한 컴 파일 경고 에 대해 충분히 중시 해 야 한다.예 를 들 어 위의 예 에서 JIT 컴 파일 러 는 Y 가 변 하지 않 았 다 고 생각 하여 순환 을 일으킨다.IA 64 플랫폼 에서 이 는 특수 한 load-acquire 접근 대신 일반 메모리 접근 으로 여 겨 져 CPU 명령 재 구성 방면 의 bug 를 초래 할 수 있 습 니 다.그러나 한 가지 예 외 는 Interlocked API 와 Thread.VolatileXXX 방법 과 자 물 쇠 를 사용 하 는 것 이다.이 API 내부 에 서 는 메모리 울타리 와 하드웨어 원자 명령 을 명시 적 으로 요구 하기 때문에 외부 공유 변수 가 volatile 수식 을 사용 하 든 말 든 상관 하지 않 습 니 다.따라서 글 에서 사용 하 는 테스트 방법 은 안전 하 다.
    이 컴 파일 경고 가 귀 찮 으 면\#pragma 명령 을 사용 하여 이러한 경 고 를 금지 할 수 있 습 니 다.다음 과 같 습 니 다.
    static volatile int x;
    
    
    
    static void Foo()
    
    {
    
    #pragma warning disable 0420
    
        Interlocked.Exchange(ref x, 1);
    
    #pragma warning restore 0420
    
    }

    물론 volatile 수식 자 를 전혀 사용 하지 않 아 도 된다.CLR 메모리 모델 은 이 점 을 보증 했다.
    volatile 을 어떻게 정확하게 사용 합 니까? ,병렬 데이터 구조:volatile 변 수 를 이야기 합 니 다.를 참고 하 세 요.

    좋은 웹페이지 즐겨찾기