경합 상태 및 교착 상태

Visual Basic .NET 또는 Visual Basic은 Visual Basic 애플리케이션에서 처음으로 스레드를 사용하는 기능을 제공합니다. 스레드는 경합 상태 및 교착 상태와 같은 디버깅 문제를 소개합니다. 이 문서에서는 이러한 두 가지 문제를 살펴봅니다.

원래 제품 버전: Visual Basic, Visual Basic .NET
원래 KB 번호: 317723

경합 상태가 발생하는 경우

경합 조건은 두 스레드가 공유 변수에 동시에 액세스할 때 발생합니다. 첫 번째 스레드는 변수를 읽고 두 번째 스레드는 변수에서 동일한 값을 읽습니다. 그런 다음 첫 번째 스레드와 두 번째 스레드는 값에 대한 작업을 수행하고 공유 변수에 마지막으로 값을 쓸 수 있는 스레드를 확인하기 위해 경합합니다. 스레드가 이전 스레드가 작성한 값 위에 쓰기 때문에 마지막 값을 작성하는 스레드의 값은 유지됩니다.

경합 상태에 대한 세부 정보 및 예제

각 스레드는 프로세서에서 실행하기 위해 미리 정의된 기간을 할당합니다. 스레드에 할당된 시간이 만료되면 스레드의 컨텍스트는 프로세서의 다음 턴까지 저장되고 프로세서는 다음 스레드의 실행을 시작합니다.

한 줄 명령으로 경합 상태를 발생시키는 방법

다음 예제를 검토하여 경합 상태가 어떻게 발생하는지 확인합니다. 두 개의 스레드가 있으며 둘 다 total 라는 공유 변수를 업데이트하고 있습니다(어셈블리 코드에서와 같이 dword ptr ds:[031B49DCh] 표시됨).

  • 스레드 1

    Total = Total + val1
    
  • 스레드 2

    Total = Total - val2
    

이전 Visual Basic 코드 컴파일의 어셈블리 코드(줄 번호 포함):

  • 스레드 1

    1. mov eax,dword ptr ds:[031B49DCh]
    2. add eax,edi
    3. jno 00000033
    4. xor ecx,ecx
    5. call 7611097F
    6. mov dword ptr ds:[031B49DCh],eax
    
  • 스레드 2

    1. mov eax,dword ptr ds:[031B49DCh]
    2. sub eax,edi
    3. jno 00000033
    4. xor ecx,ecx
    5. call 76110BE7
    6. mov dword ptr ds:[031B49DCh],eax
    

어셈블리 코드를 살펴보면 프로세서가 간단한 추가 계산을 실행하기 위해 더 낮은 수준에서 수행하는 작업 수를 확인할 수 있습니다. 스레드는 프로세서에서 해당 시간 동안 어셈블리 코드의 전부 또는 일부를 실행할 수 있습니다. 이제 이 코드에서 경합 상태가 발생하는 방식을 살펴봅니다.

Total 는 100이고, val1 50이고 val2 , 15입니다. 스레드 1 은 실행할 기회를 얻지만 1~3단계만 완료합니다. 즉 , 스레드 1 은 변수를 읽고 추가를 완료했습니다. 스레드 1 은 이제 새 값 150을 작성하기만을 기다리고 있습니다. 스레드 1이 중지되면 스레드 2가 완전히 실행됩니다. 즉, 계산한 값(85)을 변수 Total에 기록했습니다. 마지막으로 스레드 1 은 제어권을 되찾고 실행을 완료합니다. 해당 값(150)을 기록합니다. 따라서 스레드 1 이 완료되면 값 Total 은 이제 85가 아닌 150입니다.

이것이 어떻게 큰 문제가 될 수 있는지 확인할 수 있습니다. 이 프로그램이 은행 프로그램인 경우 고객은 자신의 계정에 존재하지 않아야 하는 돈이 있습니다.

이 오류는 스레드 1 이 프로세서의 시간이 만료되기 전에 실행을 완료한 다음 스레드 2 가 실행을 시작할 수 있기 때문에 임의입니다. 이러한 이벤트가 발생하면 문제가 발생하지 않습니다. 스레드 실행은 비결정적이므로 실행 시간 또는 순서를 제어할 수 없습니다. 또한 스레드는 런타임과 디버그 모드에서 다르게 실행할 수 있습니다. 또한 계열에서 각 스레드를 실행하는 경우 오류가 발생하지 않음을 확인할 수 있습니다. 이러한 임의성 때문에 이러한 오류를 추적하고 디버그하기가 훨씬 더 어려워집니다.

경합 조건이 발생하지 않도록 한 번에 하나의 스레드만 공유 변수에 액세스할 수 있도록 공유 변수를 잠글 수 있습니다. 스레드 1 및 스레드 2에도 변수가 필요한 경우 스레드 2가 스레드 1이 변수를 해제할 때까지 기다리는 동안 스레드 2의 실행이 중지되므로 이 작업을 드물게 수행합니다. 자세한 내용은 이 문서의 참조 섹션을 참조 SyncLock 하세요.

경합 상태의 증상

경합 상태의 가장 일반적인 증상은 여러 스레드 간에 공유되는 변수의 예측할 수 없는 값입니다. 이는 스레드가 실행되는 순서의 예측 불가능성으로 인해 발생합니다. 한 스레드가 승리하고 다른 스레드가 승리하는 경우도 있습니다. 다른 경우에는 실행이 올바르게 작동합니다. 또한 각 스레드가 별도로 실행되는 경우 변수 값이 올바르게 동작합니다.

교착 상태가 발생하는 경우

교착 상태는 두 스레드가 각각 다른 변수를 동시에 잠근 다음 다른 스레드가 이미 잠근 변수를 잠그려고 할 때 발생합니다. 따라서 각 스레드는 실행을 중지하고 다른 스레드가 변수를 해제할 때까지 기다립니다. 각 스레드가 다른 스레드가 원하는 변수를 보유하고 있기 때문에 아무 일도 발생하지 않으며 스레드는 교착 상태로 유지됩니다.

교착 상태에 대한 세부 정보 및 예제

다음 코드에는 및 두 개의 개체가 LeftVal 있습니다 RightVal.

  • 스레드 1

    SyncLock LeftVal
        SyncLock RightVal
            'Perform operations on LeftVal and RightVal that require read and write.
        End SyncLock
    End SyncLock
    
  • 스레드 2

    SyncLock RightVal
        SyncLock LeftVal
            'Perform operations on RightVal and LeftVal that require read and write.
        End SyncLock
    End SyncLock
    

스레드 1이 를 잠그LeftVal도록 허용되면 교착 상태가 발생합니다. 프로세서는 스레드 1의 실행을 중지하고 스레드 2의 실행을 시작합니다. 스레드 2 가 잠기 RightVal 고 가 잠기 LeftVal려고 합니다. 가 잠겨 있으므로 LeftVal스레드 2 가 중지되고 릴리스될 때까지 기다립니다 LeftVal . 스레드 2가 중지되었으므로 스레드 1은 계속 실행할 수 있습니다. 스레드 1은 잠금을 시도하지만 스레드 2가 잠 RightVal 겼기 때문에 잠글 수 없습니다. 결과적으로 스레드 1 은 RightVal을 사용할 수 있게 될 때까지 대기하기 시작합니다. 각 스레드는 다른 스레드가 대기 중인 변수를 잠그고 두 스레드가 보유하고 있는 변수의 잠금을 해제하지 않으므로 각 스레드가 다른 스레드를 대기합니다.

교착 상태가 항상 발생하는 것은 아닙니다. 스레드 1은 프로세서가 중지하기 전에 두 잠금을 모두 실행하는 경우 스레드 1은 해당 작업을 수행한 다음 공유 변수의 잠금을 해제할 수 있습니다. 스레드 1이 변수의 잠금을 해제한 후 스레드 2는 예상대로 실행을 진행할 수 있습니다.

이러한 코드 조각이 나란히 배치되는 경우 이 오류는 분명해 보이지만 실제로 코드는 코드의 별도 모듈 또는 영역에 나타날 수 있습니다. 이 동일한 코드에서 올바른 실행과 잘못된 실행이 모두 발생할 수 있으므로 추적하기 어려운 오류입니다.

교착 상태의 증상

교착 상태의 일반적인 증상은 프로그램 또는 스레드 그룹이 응답을 중지한다는 것입니다. 이를 중단이라고도 합니다. 두 개 이상의 스레드가 다른 스레드가 잠근 변수를 기다리고 있습니다. 스레드는 다른 변수를 얻을 때까지 해당 변수를 해제하지 않으므로 진행되지 않습니다. 프로그램이 해당 스레드 중 하나 또는 둘 다에서 실행을 완료하기를 기다리는 경우 전체 프로그램이 중단됩니다.

스레드란?

프로세스는 단일 컴퓨터에서 지정된 시간에 실행되는 다른 애플리케이션을 분리하는 데 사용됩니다. 운영 체제는 프로세스를 실행하지 않지만 스레드는 실행합니다. 스레드는 실행 단위입니다. 운영 체제는 스레드 태스크를 실행하기 위해 스레드에 프로세서 시간을 할당합니다. 단일 프로세스에는 여러 실행 스레드가 포함될 수 있습니다. 스레드가 프로세서에 할당된 시간 동안 스레드가 실행을 완료할 수 없는 경우 각 스레드는 자체 예외 처리기, 예약 우선 순위 및 스레드 컨텍스트를 저장하는 데 사용하는 구조 집합을 유지 관리합니다. 컨텍스트는 다음에 스레드가 프로세서 시간을 받을 때까지 유지됩니다. 컨텍스트에는 스레드가 원활하게 실행을 계속하는 데 필요한 모든 정보가 포함됩니다. 이 정보에는 스레드의 프로세서 레지스터 집합과 호스트 프로세스의 주소 공간 내의 호출 스택이 포함됩니다.

참조

자세한 내용은 Visual Studio 도움말에서 다음 키워드를 검색하세요.

  • SyncLock. 개체를 잠글 수 있습니다. 다른 스레드가 동일한 개체를 잠그려고 하면 첫 번째 스레드가 해제될 때까지 차단됩니다. 문제가 SyncLock의 오용으로 인해 발생할 수 있으므로 신중하게 사용합니다 SyncLock . 예를 들어 이 명령은 경합 상태를 방지하지만 교착 상태를 일으킬 수 있습니다.

  • InterLocked. 기본 숫자 변수에서 스레드로부터 안전한 작업 집합을 선택할 수 있습니다.

자세한 내용은 스레드 및 스레딩을 참조하세요.