2011-09-30 3 views
4

최근 루비의 스레드로 작업 해 왔으며 약간의 예상치 못한 동작이 발견되었습니다. 중요한 섹션에서 raise을 호출하면 뮤텍스가 해제됩니다. 이 블록이있는 synchronize 메서드를 예상 할 수 있지만 lockunlock을 별도로 호출하면 발생하는 것으로 보입니다.루비 예외로 인해 뮤 테이션이 잠금 해제되지 않습니다.

는 예를 들어, 아래 코드는 출력 : 나는 y 우주의 열 죽을 때까지 차단하는 기대

$ ruby testmutex.rb 
x sync 
y sync 

을 ....

m = Mutex.new 


x = Thread.new() do 
    begin 
    m.lock 
     puts "x sync" 
     sleep 5 
     raise "x err" 
     sleep 5 
    m.unlock 
    rescue 
    end 
end 


y = Thread.new() do 
    sleep 0.5 
    m.lock 
    puts "y sync" 
    m.unlock 
end 


x.join 
y.join 

x 스레드의 m.unlock이 실행되지 않는데도 왜 y 스레드가 실행될 수 있습니까?

+0

이것은 흥미로운 관찰이다. 그러나 ... 당신의 질문은 무엇입니까? Ruby 내부 구현에서 "어떻게됩니까?" 왜 이런 일이 생길까요? 의도 된 것이거나 버그입니까? – Phrogz

+0

나는 그것이 어떻게 구현 되었는가에 관해 궁금해하지만, 주된 사안은 당신이 많은 웅변으로 설명했다고 믿는 원인이다 --- 감사합니다. –

답변

2

raiseunlockx에서 제거하면 동작이 동일합니다. 따라서 x 스레드가 뮤텍스를 잠그고 스레드가 끝나고 뮤텍스가 잠금 해제 된 상황이 발생합니다.

m = Mutex.new 
Thread.new{ m.lock; p m.locked? }.join 
#=> true 

p m.locked? 
#=> false 

따라서 우리는 상황이 raise 관련이 있음을 참조하십시오. raise 주변에 begin/rescue 블록이 있으므로, 그렇지 않은 경우보다 5 초 더 일찍 x 스레드를 종료하십시오.

아마도 인터프리터는 스레드에 의해 잠긴 뮤텍스 트랙을 유지하고 스레드가 죽으면 자동으로 의도적으로 잠금을 해제합니다. (나는 소스 코드 검사를 통해이를 뒷받침 할 수 없다. 이것은 동작에 기반한 추측 일 뿐이다.)

+0

흥미를 자아냅니다. 'rescue'와'end' 사이에'sleep '을 삽입하면 멋지게 나타납니다. 잠금 장치를 해제하는 스레드의 개념은 제 기대치를 훨씬 뛰어 넘습니다. 나는 결코 루비가 그렇게 영리하지 않다고 생각하지 않았습니다. –

+1

소스 코드에서 볼 수 있습니다 : [thread.c : 338] (https://github.com/ruby/ruby/blob/trunk/thread.c#L338) –

관련 문제