|
CodeMaster 님이 쓰신 글 :
: 안녕하세요
:
: 기존에 개발되어 사용하던 32bit프로그램을 64bit으로 변환하는 과정에서 발견 된 현상있어 문의 드립니다.
:
:
: 현제 개발IDE는 Rad XE3 Update2를 사용하고 있습니다.
:
: 멀티스레드에서 로컬파일 DB접근이 동시에 이루어 질 수 있는 부분 있어
: Critical Section을 이용하여 동시접근을 제한하여 사용해 왔었습니다.
: 각 스레드에서 Critical Section 진입 및 해지(Enter, Leave)가 짝이 맞게 되어 있어
: 정상적으로 각 스레드에서 접근하여 읽기 쓰기 작업이 이루어 지며,
: windows 32bit환경으로 빌드하여 프로그램 사용시 정상동작을 확인했습니다.
:
:
: 하지만, 동일 프로그램을 windows 64bit환경으로 변경하고, 빌드하여 사용시 문제가 있었습니다.
: 한 쓰레드에서 CriticalSection 진입(EnterCriticalSection)후 나오더라도(LeaveCriticalSection)
: 다른 쓰레드에서 CriticalSection 진입시 Block되어 대기하고 있는 현상이 발생되고 있습니다.(Logging으로 문제점을 찾음)
:
: 테스트로 MS 비쥬얼스튜디오로 멀티스레드에서 CriticalSection사용하는 64bit 프로그램을 간단히
: 만들어 테스트 해보았지만, 해당 증상이 발견되고 있지는 않고 있습니다.
: 이러한 문제가 RadStudio의 C++ builder가 64bit으로 오면서 컴파일러가 LLVM Clang기반으로 추가된 것(바뀐 것?)으로 알고 있습니다.
: 이와 관련해서 생긴현상 인지도 모르겠다는 가설로, 일단 LLVM Clang에서 관련자료를 찾는 중입니다.
:
:
: 한 줄 요약
: -> '64bit에서는 LLVM Clang을 이용한 컴파일러로 인해 LeaveCriticalSection 명령이 않먹는거 같다'입니다.
:
: 혹시 관련 내용을 알고 계신분이 있으시다면 조언 부탁드립니다.
:
답변 올라온 글들 살펴보니, bcc64 (clang 기반) 컴파일러 문제라기 보단, 프로그램에 버그가 있어서일 것 같네요.
기존 32비트 프로그램이 정상적으로 돌아갔으니, 64비트로 컴파일해도 정상적으로 돌아가야 한다고 단정 하는 건...
한마디로 넌센스입니다.
예를 들어서...
포인터를 사용하는 랭귀지에서 (델파이도 마찬가지) 포인터를 편의상 습관처럼 int 타입으로 캐스팅해서 처리하는 경우가 많은데
이런 코드를 64비트로 그대로 컴파일해서 사용하면 운이 좋으면 모를까, 문제를 일으키죠. 32비트 컴파일 환경에선 포인터 크기가
4바이트지만, 64비트 환경에선 8바이트 크기라 그로인해 언더플로우/오버플로우 발생하면서 실행중 정상적으로 핸드링 되지 않는
Exception 이 탈 수도 있고... (델파이로 컴파일 되어 사용되는 VCL라이브러리도 포인터를 편의상 캐스팅 해서 사용하는 경우가
많습니다. 앰바 애들이 이런 부분을 모조리 찾아내서 조건부 컴파일을 해 놓지 않은 채 라이브러리를 배포했다면 사용자가 일일히
찾아서 해결해야 합니다.)
질문 올린 분은 위의 단정 말고도... EnterCriticalSection/LeaveCriticalSection을 짝으로 사용했고, 쓰레드 내에서 다시...
EnterCriticalSection을 호출하는 로직이 없어서 이 또한 문제가 아니라고 단정 짓고 있는데...
윈도우즈가 제공하는 CriticalSection 은... EnterCriticalSection으로 들어가서 LeaveCriticalSection으로 나왔는데도
블럭킹이 걸리는 건... CriticalSection의 InterLock 카운트가 0 이 아닐 때의 경우 밖에 없습니다. 예외처리 코드에 어떤
논리적인 버그가 있어서 LeaveCriticalSection이 어딘가에서 한번이라도 누락된 상태가 아니라면 다른 쓰레드에서
블럭킹이 걸리는 경우는 없다는 얘깁니다.
답변 올린 분이 힌트를 준거나 마찬가지 인데... RAII 패턴을 이용해서 클래스를 만들어 주고, 오브젝트를 스택변수로 선언해서
사용하면 Exception이 발생하든 안하든 RAII 패턴 객체는 항상 destructor가 호출되게 돼 있으니까 안전하게 예외와 상관없이
LeaveCriticalSection이 호출되는 것을 보장하도록 코딩이 가능합니다. RAII 패턴을 이용하면 간단하게 Exception Safety 하게
코드 구현이 가능.
여담입니다만...
예외처리를 반드시 해야할 곳에선 쓰지 않고, 예외처리가 필요없는 부분에선 쓰고, 아예 눈가리고 아웅식으로 모든 예외를
캐치해 버리는 등... 이상하게 RAD Studio툴을 사용하는 사람들 중에는 중급자들 중에서도 예외처리를 이상하게 사용하거나
함부로 남발하는 사람들이 많은 것 같습디다.
|