다양한 잠금 관련 질문을보고 (거의) 항상 ‘스퓨리어스 웨이크 때문에 루프를 찾는다’라는 용어가 궁금합니다 .1 누군가가 그런 종류의 웨이크 업을 경험 한 적이 있습니까 (예 : 괜찮은 하드웨어 / 소프트웨어 환경 가정)?
나는 ‘스퓨리어스 (spurious)’라는 용어가 명백한 이유를 의미하지는 않지만 그러한 종류의 사건에 대한 이유는 무엇입니까?
( 1 참고 : 반복 연습에 의문의 여지가 없습니다.)
편집 : 도우미 질문 (코드 샘플을 좋아하는 사람들을위한) :
다음 프로그램이 있고 실행하면
public class Spurious {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
try {
cond.await();
System.out.println("Spurious wakeup!");
} catch (InterruptedException ex) {
System.out.println("Just a regular interrupt.");
}
} finally {
lock.unlock();
}
}
}
await
임의의 이벤트를 영원히 기다리지 않고 이를 가짜 로 깨우려면 어떻게해야 합니까?
답변
가짜 웨이크 업에 관한 Wikipedia 기사 에는 다음과 같은 내용이 있습니다.
pthread_cond_wait()
Linux 의 기능은futex
시스템 호출을 사용하여 구현됩니다 .EINTR
프로세스가 신호를 수신하면 Linux의 각 차단 시스템 호출이 갑자기 리턴 됩니다. … 시스템 호출pthread_cond_wait()
이 아닌 시간에 실제 깨우기를 놓칠 수 있으므로 대기를 다시 시작할 수 없습니다futex
. 이 경쟁 조건은 호출자가 불변 값을 확인해야만 피할 수 있습니다. 따라서 POSIX 신호는 가짜 웨이크 업을 생성합니다.
요약 : 리눅스 프로세스가 신호를 받으면 대기중인 스레드는 각각 멋진 핫 스퓨리어스 웨이크 업을 즐깁니다 .
나는 그것을 산다. 일반적으로 모호한 “성능을위한”이유보다 삼키기 쉬운 피임약입니다.
답변
이 동작을 보여주는 생산 시스템이 있습니다. 스레드는 큐에 메시지가 있다는 신호를 기다립니다. 사용량이 많은 기간에는 최대 20 %의 웨이크 업이 의심됩니다 (즉, 웨이크 업시 큐에 아무것도 없음). 이 스레드는 메시지의 유일한 소비자입니다. Linux SLES-10 8 프로세서 박스에서 실행되며 GCC 4.1.2로 빌드됩니다. 시스템이 메시지를 충분히 빨리 읽지 못하면 문제가 있기 때문에 메시지는 외부 소스에서 가져오고 비동기 적으로 처리됩니다.
답변
제목의 질문에 대답하려면- 그렇습니다! 그것은 happen.Though는 않습니다 위키 문서는 내가 통해 들어와 다음 있는지 의사를 깨우는에 대해 동일한에 대한 좋은 설명을 좋은 거래를 언급 –
스레드 스케줄러는 기본 하드웨어 / 소프트웨어에서 비정상적인 문제로 인해 일시적인 정전이 발생할 수 있습니다. 물론, 이것이 가능한 한 드물게 발생하도록주의를 기울여야하지만 100 % 강력한 소프트웨어와 같은 것은 없기 때문에 스케줄러가이를 감지 할 경우 이러한 상황이 발생할 수 있고 정상적인 복구에주의를 기울이는 것이 합리적입니다 (예 : 누락 된 하트 비트를 관찰하여).
이제 스케줄러가 정전 중에 대기 스레드에 알리는 일부 신호가 누락 될 수 있다는 점을 고려하여 어떻게 스케줄러를 복구 할 수 있습니까? 스케줄러가 아무 것도하지 않으면 언급 된 “불운”스레드가 중단되어 영원히 대기합니다.이를 피하기 위해 스케줄러는 단순히 모든 대기 스레드에 신호를 보냅니다.
따라서 대기중인 스레드에 이유없이 통지 할 수있는 “계약”을 설정해야합니다. 정확히 말하면, 스케줄러 정전이 발생하는 이유가 있지만 스레드가 스케줄러 내부 구현 세부 사항에 대해 알 수 없도록 설계되었으므로이 이유는 “스퓨리어스”로 표시하는 것이 좋습니다.
나는 출처 에서이 답변을 읽었 으며 충분히 합리적이라고 생각했습니다. 또한 읽으십시오
추신 : 위의 링크는 가짜 모닝콜에 대한 추가 세부 정보가있는 개인 블로그로 연결됩니다.
답변
Cameron Purdy 는 블로그 게시물을 작성했습니다 가짜 모닝콜 문제에 부딪 치는 것에 대해 . 네, 그래요
Java가 배포되는 일부 플랫폼의 제한 때문에 사양에 있다고 생각합니다. 내가 틀렸을 수도 있지만!
답변
이것을 추가하십시오. 그렇습니다. 24 코어 시스템 (JDK 6)에서 멀티 스레딩 문제의 원인을 검색하는 데 3 일이 걸렸습니다. 10 건 중 4 건은 아무런 패턴없이 그 경험을했습니다. 이것은 2 코어 또는 8 코어에서 발생하지 않았습니다.
일부 온라인 자료를 연구했으며 이는 Java 문제가 아니라 일반적이지만 드물지만 예상되는 동작입니다.
답변
https://stackoverflow.com/a/1461956/14731 에는 기본 운영 체제가 트리거하지 않는 경우에도 가짜 웨이크 업으로부터 보호해야하는 이유에 대한 훌륭한 설명이 포함되어 있습니다. 이 설명은 Java를 포함한 여러 프로그래밍 언어에 적용됩니다.
답변
OP의 질문에 답변
무작위 이벤트를 영원히 기다리지 않고이 대기를 깨우려면 어떻게해야합니까?
, 어떤 가짜 모닝콜 도이 기다리는 스레드를 깨울 수 없습니다 !
에 관계없이 의사를 깨우는가 또는 영업의의 경우, 특정 플랫폼에서 일어날 수 있는지 여부의는 긍정적이다 니펫을 불가능 에 대한 Condition.await()
반환하고 라인을보고 “가짜 웨이크 업!” 출력 스트림에서.
매우 이국적인 Java 클래스 라이브러리를 사용하지 않는 한
표준 때문이다 오픈 JDK 의 ReentrantLock
의 방법 newCondition()
반환 AbstractQueuedSynchronizer
‘의의 구현 Condition
중첩 된 인터페이스, ConditionObject
(그런데, 그것의 유일한 구현 Condition
이 클래스 라이브러리 인터페이스), 그리고 ConditionObject
의 방법 await()
조건이되지 않습니다 여부를 자체 점검 보류하고 가짜 웨이크 업으로 인해이 메소드가 실수로 리턴되지 않을 수 있습니다.
그건 그렇고, 일단 AbstractQueuedSynchronizer
기반 구현이 포함 되면 가짜 모닝콜을 모방하기가 쉽기 때문에 직접 확인할 수 있습니다 .
AbstractQueuedSynchronizer
낮은 수준의 사용 LockSupport
의 park
와 unpark
방법, 그리고 경우에있는 invoke LockSupport.unpark
에 대기중인 스레드에 Condition
,이 작업은 가짜 웨이크 업 구별 할 수 없습니다.
OP의 스 니펫을 약간 리팩토링
public class Spurious {
private static class AwaitingThread extends Thread {
@Override
public void run() {
Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
try {
cond.await();
System.out.println("Spurious wakeup!");
} catch (InterruptedException ex) {
System.out.println("Just a regular interrupt.");
}
} finally {
lock.unlock();
}
}
}
private static final int AMOUNT_OF_SPURIOUS_WAKEUPS = 10;
public static void main(String[] args) throws InterruptedException {
Thread awaitingThread = new AwaitingThread();
awaitingThread.start();
Thread.sleep(10000);
for(int i =0 ; i < AMOUNT_OF_SPURIOUS_WAKEUPS; i++)
LockSupport.unpark(awaitingThread);
Thread.sleep(10000);
if (awaitingThread.isAlive())
System.out.println("Even after " + AMOUNT_OF_SPURIOUS_WAKEUPS + " \"spurious wakeups\" the Condition is stil awaiting");
else
System.out.println("You are using very unusual implementation of java.util.concurrent.locks.Condition");
}
}
unparking (main) 스레드가 대기중인 스레드를 깨우려고 시도해도 아무리 어려운 경우에도이 Condition.await()
메서드는 반환되지 않습니다.
Condition
대기중인 메소드 에 대한 가짜 깨우기 는 Condition
인터페이스 의 javadoc 에서 논의됩니다 . 그렇게 말하지만
조건을 기다릴 때 가짜 웨이크 업이 발생할 수 있습니다
그리고
응용 프로그램 프로그래머는 항상 발생할 수 있다고 가정하므로 항상 루프에서 기다리십시오.
하지만 나중에 추가합니다
가짜 웨이크 업 가능성을 제거하는 구현은 자유 롭다
그리고 인터페이스 AbstractQueuedSynchronizer
의 구현 은 스퓨리어스 웨이크 업의 가능성을 제거합니다 .Condition
이것은 다른 ConditionObject
대기중인 방법에 대해서도 마찬가지입니다 .
그래서, 결론은 다음과 같습니다
우리는 항상 Condition.await
루프를 호출 하고 조건이 유지되지 않는지 확인해야하지만 표준 OpenJDK를 사용하면 Java 클래스 라이브러리가 발생할 수 없습니다 . 다시 한 번, 매우 특이한 Java 클래스 라이브러리를 사용하지 않는 한 (현재 거의 멸종 된 GNU Classpath 및 Apache Harmony 로 알려진 다른 OpenJDK Java 클래스 라이브러리 는 표준 Condition
인터페이스의 표준 구현과 동일한 것으로 보이므로 매우 예외적 임 )