잠금은 정확히 어떻게 작동합니까?


527

스레드로부터 안전하지 않은 객체를 사용하려면 다음과 같이 잠금으로 코드를 래핑합니다.

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

따라서 여러 스레드가 동일한 코드에 액세스하면 어떻게됩니까 (ASP.NET 웹 응용 프로그램에서 실행되고 있다고 가정합니다). 그들은 대기열에 있습니까? 그렇다면 얼마나 오래 기다 립니까?

잠금 사용으로 인한 성능 영향은 무엇입니까?


답변:


448

lock문장은 C # 3.0에 의해 다음과 같이 번역됩니다.

var temp = obj;

Monitor.Enter(temp);

try
{
    // body
}
finally
{
    Monitor.Exit(temp);
}

C # 4.0에서는 이것이 변경 되었으며 이제 다음과 같이 생성됩니다.

bool lockWasTaken = false;
var temp = obj;
try
{
    Monitor.Enter(temp, ref lockWasTaken);
    // body
}
finally
{
    if (lockWasTaken)
    {
        Monitor.Exit(temp); 
    }
}

당신은 무엇에 대한 자세한 정보를 찾을 수 있습니다 Monitor.Enter않습니다 여기를 . MSDN을 인용하려면 :

Enter매개 변수로 전달 된 오브젝트에서 모니터를 획득하는 데 사용하십시오 . 다른 스레드가 Enter 객체에서 실행했지만 해당를 아직 실행하지 않은 Exit경우 다른 스레드가 객체를 해제 할 때까지 현재 스레드가 차단됩니다. 동일한 스레드가 Enter차단없이 두 번 이상 호출하는 것이 합법적입니다 . 그러나 Exit객체를 기다리는 다른 스레드가 차단을 해제하기 전에 동일한 수의 호출 을 호출해야합니다.

Monitor.Enter방법은 무한정 기다릴 것입니다. 그것은 것입니다 하지 타임 아웃.


15
MSDN에 따르면 잠금 또는 SyncLock이 더 간결하고 잠금 또는 SyncLock으로 인해 기본 모니터가 해제되기 때문에 일반적으로 잠금 (C #) 또는 SyncLock (Visual Basic) 키워드를 사용하는 것이 Monitor 클래스를 직접 사용하는 것보다 일반적으로 선호됩니다 보호 된 코드에서 예외가 발생하면 finally 키워드를 사용하여 예외가 발생하는지 여부에 관계없이 관련 코드 블록을 실행합니다. " msdn.microsoft.com/ko-kr/library/ms173179.aspx
Aiden Strydom

10
var temp = obj의 요점은 무엇입니까? 선. 그것은 시작에 대한 참조 일 뿐이므로 다른 것을 만드는 것이 무엇을 하는가?
priehl

11
@priehl obj전체 시스템없이 교착 상태 로 변경할 수 있습니다 .
Steven

7
@Joymon은 결국 모든 언어 기능이 구문 설탕입니다. 언어 기능은 잠금 기능과 마찬가지로 개발자의 생산성을 높이고 응용 프로그램을 유지 관리하기 쉽게 만드는 것입니다.
Steven

2
옳은. 이것은 lock-statement 및 Monitor 의 전체 목적입니다 . 따라서 다른 스레드가이를 방해하지 않아도 하나의 스레드에서 작업을 수행 할 수 있습니다.
Dizzy H. Muffin 2016 년

285

생각보다 간단합니다.

Microsoft 에 따르면 : lock키워드는 한 스레드가 중요한 코드 섹션에 들어 가지 않고 다른 스레드가 중요한 섹션에 있도록합니다. 다른 스레드가 잠긴 코드를 입력하려고하면 객체가 해제 될 때까지 기다립니다.

lock키워드는 호출 Enter블록의 시작과 Exit블록의 끝에서. lock키워드는 실제로 Monitor백엔드에서 클래스를 처리합니다 .

예를 들면 다음과 같습니다.

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

위의 코드에서 스레드는 먼저 임계 구역으로 들어간 다음 잠 깁니다 obj. 다른 스레드가 들어 가려고 할 때 obj이미 첫 번째 스레드에 의해 잠긴 lock을 시도합니다 . 두 번째 스레드는 첫 번째 스레드가 해제 될 때까지 기다려야합니다 obj. 첫 번째 스레드가 떠나면 다른 스레드가 잠기고 obj중요한 섹션으로 들어갑니다.


9
잠글 더미 객체를 만들어야합니까 아니면 컨텍스트에서 기존 변수를 잠글 수 있습니까?
batmaci

9
@batmaci-별도의 개인용 더미 개체를 잠그면 다른 사람이 해당 개체를 잠그지 않을 수 있습니다. 데이터를 잠그고 동일한 데이터를 외부에서 볼 수 있으면 해당 보증을 잃게됩니다.
Umar Abbas

8
둘 이상의 프로세스가 잠금 해제를 기다리는 경우 어떻게됩니까? 대기 프로세스가 FIFO 순서로 중요 섹션을 잠그도록 큐에 대기됩니까?
jstuardo

@jstuardo-대기열에 있지만 주문이 FIFO 인 것은 아닙니다. 이 링크를 확인하십시오 : albahari.com/threading/part2.aspx
Umar Abbas


47

아니, 그들은 대기하지 않고, 자고있다.

양식의 잠금 문

lock (x) ... 

여기서 x는 참조 유형의 표현식입니다.

var temp = x;
System.Threading.Monitor.Enter(temp); 
try { ... } 
finally { System.Threading.Monitor.Exit(temp); }

당신은 그들이 서로 기다리고 있다는 것을 알아야하며, 하나의 스레드 만 블록을 잠그기 위해 들어가고 다른 스레드는 기다릴 것입니다 ...

모니터는 .net으로 완전히 작성되었으므로 충분히 빠릅니다. 자세한 내용 은 리플렉터 가있는 모니터 클래스 를 참조하십시오.


6
lock명령문에 대해 생성 된 코드 는 C # 4 ( blogs.msdn.com/b/ericlippert/archive/2009/03/06/…)
LukeH

@ArsenMkrt, "차단됨"상태 "대기열"로 유지되지 않습니다. 절전 모드와 차단 상태간에 약간의 차이가 있다고 생각합니까?
Mohanavel

@Mohanavel은 무슨 차이가 있습니까?
Arsen Mkrtchyan

1
그것은 질문이 아니 었습니다. 질문은 "잠금"키워드에 관한 것이 었습니다. 프로세스가 "잠금"섹션으로 들어간다고 가정하십시오. 이는 프로세스가 해당 코드 조각을 차단하고 해당 잠금이 해제 될 때까지 다른 프로세스가 해당 섹션에 들어갈 수 없음을 의미합니다. 글쎄 .. 이제 2 개의 프로세스가 같은 블록에 들어 가려고합니다. "lock"키워드로 보호되므로이 포럼에서 말한 내용에 따라 대기합니다. 첫 번째 프로세스가 잠금을 해제 할 때 어떤 프로세스가 블록에 들어 갑니까? 처음으로 들어 가려고 했습니까?
jstuardo

1
나는 당신이 프로세스 대신 스레드를 의미한다고 생각합니다 ... 그렇다면, 대답이 아니오보다, 어떤 것이 들어갈 것인지 보장 할 수는 없습니다 ... more here stackoverflow.com/questions/4228864/…
Arsen Mkrtchyan

29

잠금은 다른 스레드가 잠금 블록에 포함 된 코드를 실행하지 못하도록 차단합니다. 스레드는 잠금 블록 내부의 스레드가 완료되고 잠금이 해제 될 때까지 기다려야합니다. 이것은 다중 스레드 환경에서 성능에 부정적인 영향을 미칩니다. 이를 수행해야하는 경우 잠금 블록 내의 코드가 매우 빠르게 처리 될 수 있는지 확인해야합니다. 데이터베이스 액세스 등과 같은 값 비싼 활동을 피해야합니다.


11

성능 영향은 잠금 방식에 따라 다릅니다. http://www.thinkingparallel.com/2007/07/31/10-ways-to-reduce-lock-contention-in-threaded-programs/ 에서 좋은 최적화 목록을 찾을 수 있습니다 .

기본적으로 대기 코드를 잠자기 때문에 가능한 한 적게 잠그십시오. 잠금에 많은 계산이나 오래 지속되는 코드 (예 : 파일 업로드)가있는 경우 성능이 크게 저하됩니다.


1
그러나 로우 록 코드를 작성하려고하면 해당 분야의 전문가라도 미묘하고 찾기 어려운 버그가 발생할 수 있습니다. 자물쇠를 사용하는 것은 종종 두 가지 악의 적은 것입니다. 더 이상, 더 이상, 필요한만큼 정확하게 고정해야합니다!
LukeH

1
@LukeH : 로우 록 코드가 매우 간단하고 쉬울 수있는 몇 가지 사용 패턴이 있습니다 [ do { oldValue = thing; newValue = updated(oldValue); } while (CompareExchange(ref thing, newValue, oldValue) != oldValue]. 가장 큰 위험은 이러한 기술이 처리 할 수있는 것 이상으로 요구 사항이 발전하는 경우이를 처리하기 위해 코드를 조정하기가 어렵다는 것입니다.
supercat

링크가 끊어졌습니다.
CarenRose

8

잠금 명령문 내의 파트는 하나의 스레드 만 실행할 수 있으므로 다른 모든 스레드는 잠금을 보유한 스레드가 완료 될 때까지 무기한 대기합니다. 이로 인해 소위 교착 상태가 발생할 수 있습니다.


8

lock명령문은의 EnterExit메소드 호출로 변환됩니다 Monitor.

lock잠금 개체가 해제 될 때까지 문이 무기한 기다립니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.