2013-11-25 3 views
1

나는 다중 프로그래밍의 예술이라는 책을 읽고 있었다 등이 있다고 책에서 등함수는 어떻게 원자 적이됩니까?

의 get(), getandset()의 compareAndSet(), getandIncrease(), getandIncrease()와 같은 기능을 통해 온 한 위의 모든 함수는 원자 적이며 동의하지만 어떤 함수가 원자 함수가되는 방법에 대한 내 자신의 의문이 생겼습니다.

와 함수는를 얻을 않거나 원자 될 비교할? 왜냐하면 그것이 가치를 얻을 때까지 기다려야하기 때문이거나 어떤 조건이 사실이되어서 장벽을 만들어서 원자가 될 때까지 기다리기 때문입니다.

나는 이런 식으로 생각하고 있니? 내가 놓친 것이 있습니까?

내가

if (tail_index.get() == (head_index.getAndIncrement()) 

할 때 원자입니까?

+3

원자는 "불가분"을 의미합니다. 원자 적 조작의 일부는 볼 수 없으며 모든 작업은 한 번에 발생하는 것처럼 보입니다. 귀하의 경우에는 두 가지 get 메소드가 하나로 수행되도록 보장 할 수있는 것이 없으므로 나는 그것을 원자라고 부르지 않을 것입니다. –

답변

1

순간적으로 나타나는 경우 함수는 원자입니다.

여기서 "나타납니다"는 나머지 시스템을 의미합니다. 예를 들어 링크 된 목록을 뒤집는 동기화 된 함수를 생각해보십시오. 외부 관찰자에게는 작업이 즉각적으로 발생하지 않는다 : 모든 목록 포인터를 업데이트하기 위해 많은 읽기 및 쓰기가 필요합니다. 그러나 잠금이 전체 시간 동안 유지되므로이 시간 동안 시스템의 다른 부분이 목록을 읽을 수 없으므로 업데이트가 즉시 나타납니다.

마찬가지로 CAS (비교 및 설정) 작업 은 실제로 최신 컴퓨터에서 즉시 발생합니다. 하나의 CPU 코어가 값에 대한 독점 쓰기 액세스를 얻는 데는 시간이 걸리고 나중에 다른 코어가 새로운 값을보기 위해 읽기 액세스를 다시 얻는 데 더 많은 시간이 걸립니다. 이 시간 동안 CPU는 다른 명령어를 병렬로 실행합니다.즉각적인 실행을 보장하기 위해 JVM은 CAS 작업 전후에 CPU 명령어를 실행하여 CAS가 완료되기 전에 논리적으로 연속적인 읽기가 풀리고 실행되지 않도록합니다 (이렇게하면 이전에 링크 된 목록의 일부를 읽을 수 있습니다). 예를 들어 잠금을 실제로 가져 왔음) CAS가 완료된 후에 논리적으로 선행하는 쓰기가 지연되고 실행되지 않습니다 (링크 된 목록이 완전히 업데이트되기 전에 다른 스레드가 잠금을 허용 함).

이러한 CPU 주문 지침은 AtomicInteger.compareAndSetAtomicInteger.weakCompareAndSet 사이의 주요 차이입니다 ("거짓으로 실패 할 수 있음"비트는 루프로 쉽게 수정 될 수 있음). 순서 보장이 없으면 약한 CAS 연산을 사용하여 대부분의 동시 알고리즘을 구현할 수 없으며 "compareAndSet에 대한 적절한 대안"으로 만 취급됩니다.

이것이 들리는 경우 ... 음 ... 그렇습니다! 그래서 you can still get a PhD by designing a concurrent algorithm입니다. 동시 알고리즘의 정확성을 나타 내기 위해서는 다른 모든 스레드가 사용자를 혼란에 빠뜨리기 위해 할 수있는 일을 고려해야합니다. 원 자성의 환상을 깨려고 애쓰면서 상대방을 상대방으로 생각하면 도움이 될 수 있습니다. 나는이는 "만약"는 경우의 몸을 인덱스 카운터와주기적인 배열로 구현 된 스택에서 항목을 팝업 및 실행하는 방법의 일부입니다 가정

if (tail_index.get() == (head_index.getAndIncrement())) 

: 예를 들어, 귀하의 예를 살펴 보자 스택이 비어 있습니다. head_index와 tail_index는 별도로 액세스되기 때문에 상대방이 원하는만큼의 작업으로 "분할"할 수 있습니다. 예를 들어 스레드가 get과 getAndIncrement 사이의 OS에 의해 중단되었다고 상상해보십시오. 따라서 수십 개의 항목을 스택에 추가 한 다음 하나만 제외하고 모두 제거하십시오. tail_index ; 스택의 마지막 항목을 제거하더라도 if 블록은 실행되지 않습니다.

그래서 책에 get(), getAndSet() 등이 원자적일 경우 해당 메소드의 가능한 구현에 대한 일반적인 설명을하지 않습니다. Java 표준 인 은 원자 단위이며, 사용 가능한 CPU 명령어를 신중하게 사용함으로써 평범한 Java로 수행 할 수없는 방식으로을 보장한다는 것을 알려줍니다 (synchronized로 에뮬레이트 할 수 있습니다. 더 많은 비용이 소요됨).

4

명백한 스레드 안전성을 추가하여 일부 인스턴스와 관련된 메서드가 만들어졌습니다 (atomic). 대부분의 경우이 방법은 synchronized으로 표시하여 수행합니다. 마술은 없습니다. 메서드가 원자 적이라고 주장하는 스레드로부터 안전한 클래스의 소스 코드를 보면 잠금이 표시됩니다.

두 번째 부분에 WRT, 아니요 원자가 아닙니다. 각각의 메소드 호출은 원 자성이지만 두 개를 합치면 결합이 원자가되지 않습니다. getgetAndIncrement은 명시 적으로 원자 적으로 처리되었습니다. 일단 다른 코드 (또는 호출의 조합)를 추가하면 그렇게하지 않으면 원자가되지 않습니다.

+0

John에게 답변 해 주셔서 감사합니다. 나는 아직도 두 개의 원자 적 연산이 결합되어있을 때 어떻게 조합이 원자 적이 아닌지에 대해 혼란 스럽다. 그것은 각각 분리 된 스레드에서 원자와 원자가 구멍처럼 느슨해지기 때문입니까? 순차적 인 일관성은 구성 적이 아닌가? – solti

+0

각각이 별도의 스레드에 있기 때문에 단일 스레드가 원 자성이 아니기 때문이 아닙니다. 생각해 보면,'get'은 들어가서 잠금을 얻습니다. 종료 전에 잠금을 해제합니다. 그런 다음 JVM은'getAndIncrement'를 호출하기 전에 추가 세트를 취할 수 있습니다 (|| 확인). 다시 취득하려고 시도하기 전에 잠금 장치가 해제 될 때마다 다른 장치가 들어올 가능성이 있습니다. –

+2

BTW '동기화 된'잠금 또는 잠금 장치가없는 AtomicXxxx 클래스는 없습니다. –

1

아니요, 기능을 사용하면 get()을 사용할 수 없습니다. 그러나 예를 들어, getAndIncrement 또는 compareAndSet은 원자 자체입니다. 그것은 모든 논리가 원자 적으로 이루어진다는 것을 보장한다는 것을 의미합니다. get()에 대해서는 또 다른 확신이 있습니다. 하나의 스레드에 원자 값을 게시하면 즉시 다른 스레드에서 볼 수있게됩니다 (휘발성 필드처럼). 비 휘발성 및 비 원자 값은 없습니다 : 비 휘발성으로 설정된 값이 다른 스레드에 표시되지 않는 경우가 있습니다. 이 쓰레드는 필드 값을 읽는 오래된 값을 얻는다.

하지만 언제나 Atomic* 클래스 및 기타 synchonization 프리미티브를 사용하여 원자 함수를 작성할 수 있습니다.