2012-01-09 2 views
5

synchronized 블록을 사용하는 CMU Sphinx Speech Recognizer 라이브러리 (Link to source)를 사용하고 있습니다. RecognizerTask에서다중 스레드 정확성 : 동기화 된 블록 사용

한 예 블록 : 가드 RecognizerTask.mailbox에 동기화 헛된 시도 :

버그 :

코드는 아무 문제없이 작동
Event mailbox; 

[...] 

public void start() { 
    synchronized (this.mailbox) { 
     this.mailbox.notifyAll(); 
     this.mailbox = Event.START; 
    } 
} 

그러나 BugFinder이 경고를 제공합니다 그것

이 방법은 동시 발생을 막기위한 것으로 보이는 필드에서 동기화됩니다 해당 필드에 대한 업데이트. 그러나 필드를 지키고있는 은 필드가 아니라 참조 된 개체에 대한 잠금을 가져옵니다. 다른 사용자가 필요로하는 상호 배타를 제공하지 않을 수 있으며 다른 스레드가 참조 된 객체에 대한 잠금을 획득 할 수 있습니다 (다른 목적). 이 패턴의 예는 다음과 같습니다

private Long myNtfSeqNbrCounter = new Long(0); 
private Long getNotificationSequenceNumber() { 
    Long result = null; 
    synchronized(myNtfSeqNbrCounter) { 
     result = new Long(myNtfSeqNbrCounter.longValue() + 1); 
     myNtfSeqNbrCounter = new Long(result.longValue()); 
    } 
    return result; 
} 

솔직히 말해서, 나는 꽤 버그 설명을 이해하지 못하는 어떤 생각되어이 경우 잘못 될 수 있습니다. 전역 변수가 필드가 아닌가? 그렇다면 코드를 어떻게 개선 할 수 있습니까?/편집

:

Event todo = Event.NONE; 
     synchronized (this.mailbox) { 
      todo = this.mailbox; 
      /* If we're idle then wait for something to happen. */ 
      if (state == State.IDLE && todo == Event.NONE) { 
       try { 
        //Log.d(getClass().getName(), "waiting"); 
        this.mailbox.wait(); 
        todo = this.mailbox; 
        //Log.d(getClass().getName(), "got" + todo); 
       } catch (InterruptedException e) { 
        /* Quit main loop. */ 
        //Log.e(getClass().getName(), "Interrupted waiting for mailbox, shutting down"); 
        todo = Event.SHUTDOWN; 
       } 
      } 
      /* Reset the mailbox before releasing, to avoid race condition. */ 
      this.mailbox = Event.NONE; 
     } 

이 코드는 실제로뿐만 아니라 synchronized 문을 사용한다 : 이것은 Event.wait()가 호출되는 유일한 부분입니다. 그것을 사용하는 것이 전혀 의미가 있습니까?

답변

3

귀하의 경우에는 해당되지 않는다고 생각합니다.

synchronized (this.mailbox) { 
    this.mailbox.wait();   
} 

통지를 기다리는 동안 다른 스레드가 잠금을 포기하는 것을 의미 : 당신은 어딘가 다른 스레드의 코드에 일치하는 wait() 전화가 있음을 의미 notifyAll()를 호출합니다.

에 코드를 관리자가 아마도 선으로 혼란 :

this.mailbox = Event.START; 

는 동시에,이 객체를 수정 될 수 있음을 의미 다른 스레드가 this.mailbox에 대한 잠금을 얻기 위해 시도하는 경우, 그것은 다른 개체를 볼 수 있도록 . 잠금이 울타리를 생성

  • 모든 스레드가 동기화의 업데이트 된보기를해야

    1. this.mailbox 참조
    2. 양수인이 원자이다 세계적으로 볼 수 있습니다 : 그러나, 이후 있다고 생각하십니까 언제나 반대한다.

    +0

    정확합니다. 동기화가 대부분의 사람들이 생각하는대로하지 않는다는 경고가 정확합니다. 그러나이 경우 중요하지 않습니다. 쓰레드는 중요하지 않은 곳에 '잘못된'자물쇠만을 붙잡고있다. '부적절한'잠긴 코드는 원자 적으로 참조를 할당하기 때문에 자물쇠가 필요 없다. –

    +0

    답변 해 주셔서 감사합니다. 내 업데이트 된 질문을 참조하십시오 -'synchronized '를 완전히 제거 하시겠습니까? – Force

    +1

    개체에 대한 알림 또는 알림/통지는 동일한 개체의 동기화 된 블록 안에 있어야하기 때문에 실제로는 할 수 없습니다. – Tudor

    3

    mailbox으로 표시된 개체의 경우 동기화 된 블록은 지정된 개체에 대한 잠금을 "캡처합니다". 변수 mailbox을 다른 객체를 가리 키도록 변경하면 다른 스레드가이 객체에 대한 잠금을 문제없이 "캡처"할 수 있으므로 캡처되지 않습니다.

    잠금 장치는 참조 용이 아니라 개체 용입니다.

    synchronised (myObject) { 
        myObject = new Object(); 
        i += 5; //assume i is an instance variable 
    } 
    

    실질적으로 여기에는 잠금 장치가없는 다음 [의사 코드] 재질 - 구글 번역 참고 이제

    ! 모든 스레드가 잠금 블록에 새 객체를 만들고있어 수정이 동기화되지 않았습니다!

    +1

    그래서 우리는 최종 개체를 만들고이를 잠금에 사용해야합니다. –

    +0

    답변 해 주셔서 감사합니다. 내 업데이트 된 질문을 참조하십시오 -'synchronized '를 완전히 제거 하시겠습니까? – Force