경합 상태 및 교착 상태
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
. 기본 숫자 변수에서 스레드로부터 안전한 작업 집합을 선택할 수 있습니다.
자세한 내용은 스레드 및 스레딩을 참조하세요.
피드백
https://aka.ms/ContentUserFeedback
출시 예정: 2024년 내내 콘텐츠에 대한 피드백 메커니즘으로 GitHub 문제를 단계적으로 폐지하고 이를 새로운 피드백 시스템으로 바꿀 예정입니다. 자세한 내용은 다음을 참조하세요.다음에 대한 사용자 의견 제출 및 보기