블로그 이미지
대갈장군

calendar

1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

Notice

2010. 3. 11. 00:29 프로그래밍/C
예전에 다른 글에서 Visual Studio의 Code Generation 옵션에 대해서 이야기 한 적이 있다. 

위 글에서는 간단하게 옵션에 대한 설명만 했지만 왜 싱글 스레드에서 멀티 스레드로 바뀌었는지에 대해서는 충분히 설명하지 못했다. 그래서 이 글을 추가로 작성한다.

C 언어는 멀티 스레드 개념이 생기기 이전의 언어이므로 멀티 스레드 환경에서 발생하는 자원 경쟁 상태 (Race Condition)을 염두해 두지 않았다. 즉, 여러개의 스레드가 하나의 전역 변수를 공유하여 서로 바꾸려고 할때 발생하는 경쟁 상태를 말하는데 이것의 대표적인 예로 C 언어의 errno 전역 변수이다.

이 전역 변수는 호출한 함수의 결과를 저장하는 전역 변수인데 싱글 스레드의 경우에는 아무런 문제가 없으나 멀티 스레드의 경우 임의의 함수 호출 후 다른 스레드가 또 다른 함수를 호출하여 그 결과를 errno에 저장해 버릴 수 있기 때문에 100% 신뢰할 수 있는 결과를 가지지 않는다. 

그래서 Microsoft사에서 내놓은 해결책이 멀티 스레드를 위한 새로운 런타임 라이브러리 사용이었다. 멀티 스레드를 위한 런타임 라이브러리는 멀티 스레드에서도 안정적인 C 함수들을 호출하므로 100% 신뢰할 수 있다. 


내가 늘 불만인 것은 Visual Studio는 이렇게 중요한 옵션에 대한 설명이 너무나 부족하다는 것이다. 초보 프로그래머는 절대로 "왜 이걸 써야 하지?" 라는 궁극적인 질문에 대답을 할 수 없다.

MSDN에 설명이 되어 있다고 하지만 그 마저도 C 언어를 안다는 가정하에 설명하고 있어서 읽다가 짜증만 난다. 쉽게 쉽게 풀어서 설명해 주면 안되겠니? 응?

아무튼, 배포를 위한 프로그램을 개발한다면 거의 /MD를 사용하면 된다. D가 의미하는 것이 다이나믹 링크이므로 프로그램을 설치할 컴퓨터에 Visual Studio C++ 런타임 라이브러리만 잘 설치되어 있으면 프로그램은 무리 없이 돌아갈 것이다.

하지만 한가지 더 중요한 것은 이렇게 /MD 설정으로만 모든 것이 해결되는 것은 아니며 스레드 생성시 반드시 _beginthreadex() 함수를 사용해라는 것인데, 이 함수는 스레드 생성 전에 스레드를 위한 독립 저장 공간을 생성하여 자원 경쟁을 예방한다. 이런 독립 공간을 스레드 지역 저장소라하며 원어로를 Thread Local Storage 라 부른다. 

그리고 생성을 저 함수로 했다면 스레드를 죽일때에는 _endthreadex()를 사용해야 한다. 

결론적으로,
  • C 언어는 싱글 스레드를 근간으로 작성되었으므로 멀티 스레드의 자원 경쟁 문제를 유발할 수 있다.
  • 그런 발생 가능한 문제 제거를 위해서는 멀티 스레드 런타임 라이브러리 옵션 (/MD)를 사용하면 된다.
  • 완벽한 문제 발생 제거를 위해서는 _beginthreadex()_endthreadex() 함수로 스레드를 생성하고 해제하라.


'프로그래밍 > C' 카테고리의 다른 글

C Language Constructors and Destructors with GCC  (0) 2015.02.12
C Standard Library  (0) 2010.09.25
호출 규약  (0) 2009.07.28
posted by 대갈장군
2008. 10. 22. 06:20 프로그래밍/MSDN

참고 자료: http://msdn.microsoft.com/en-us/library/abx4dbyh(VS.80).aspx

관련글: http://diehard98.tistory.com/entry/MSDN-Manifest-파일 (manifest 파일에 대한 설명 및 재배포 방법)


Visual Studio 2005의 C++를 이용해서 프로그램을 작성하다 보면 프로젝트의 Properties 에서 Code Generation 속성에 보면 /MT, /MTd, /MD, /MDd 와 같은 다양한 형태의 옵션 설정이 가능하다.

이것을 어떻게 설정하는가에 따라서 내가 만드는 프로그램이 어떤 DLL과 연결이 되는지정적(Static)으로 라이브러리를 링크 할 것인지 아니면 동적(Dynamic)으로 라이브러리를 링크 할 것인지를 결정할 수 있다.

이 속성을 우습게 보았다가 나는 큰 코 다쳤다. =_+ 헐

Standard C++ Library

Characteristics

Option

Preprocessor directives

LIBCPMT.LIB

Multithreaded, static link

/MT

_MT

MSVCPRT.LIB

Multithreaded, dynamic link (import library for MSVCP80.dll)

/MD

_MT, _DLL

LIBCPMTD.LIB

Multithreaded, static link

/MTd

_DEBUG, _MT

MSVCPRTD.LIB

Multithreaded, dynamic link (import library for MSVCP80D.DLL)

/MDd

_DEBUG, _MT, _DLL


일단, 위의 테이블은 내가 프로그램에서 Standard C++ Library에 해당되는 헤더 파일을 불러왔을 경우에 연결되는 라이브러리들을 보여준다.

Standard C++ Library라 함은 http://en.wikipedia.org/wiki/C_Standard_Library 에 나와 있는 헤더들을 말한다. 아마도 기본적인 프로그램을 작성한다면 최소한 저것 중에 하나는 들어가게 된다.

물론 아닌 사람도 있겠지만... 헐헐헐...

아무튼, 그런 경우가 아니면, 링크 되는 라이브러리가 바뀌긴 한다만 영어 철자 하나 차이로 바뀐다. 일단은 Standard C++ Library를 사용한다고 생각하자.

원래 과거에는 (정확히는 모르겠지만 Visual Studio 6 까지 일것이다.) Single Thread 옵션도 지원이 되었다. 하지만 Visual Studio 2005에서는 무조건 Multi Thread로 프로그램을 작성해야 한다.

앞서 내가 작성한 글에도 있지만 C 런타임 라이브러리가 옛날에 작성될 때 Thread란 개념이 없다보니 Multi Thread로 동작하는 프로그램의 경우 '자원 경쟁'에 의한 오작동 했다.

아마도 이런 문제를 싸그리 날려버리기 위해서 2005에서는 오직 Multi Thread만 지원하나 보다.

표에 보면 /MT와 /MTd가 있는데 이 소문자 d는 Debug 버전을 의미한다. 나도 사실 Debug와 Release의 차이를 전혀 모르다가 다른 컴퓨터에 내 프로그램을 설치하면서 그 차이를 알게 되었다.

간단히 말해서 Debug 버전은 해당 Visual Studio가 설치된 컴퓨터에서만 '테스트'용으로 사용한다. 즉, Visual Studio가 설치안된 컴퓨터에다가 Debug 버젼으로 완성된 .exe 파일 들고가서 실행해봐야 실행이 안되고 The system cannot run this program. 어쩌구 저쩌구 그런다.

왜냐면 Debug 버젼은 실행시 링크되어야 할 DLL 파일이 Visual Studio가 설치되지 않은 컴퓨터의 .NET Framework Assembly 폴더인 Windows/WinSxS 폴더에 존재하지 않기 때문이다.

또한 ELUA인가 뭔가에 의해서 Debug 버전의 DLL 파일은 재배포가 금지되어 있다. 즉, 배포를 목적으로 한다면 Release 버전으로 작성하라~ 이말이다.

아무튼, 테이블에서 보이는 한가지 더 특별한 차이는 Static 과 Dynamic 링크이다. Static 링크는 실행 파일에다가 필요한 DLL 을 같이 묶어서 .exe 파일로 만든다. (개념적으로 그렇긴 한데 DLL 전체를 포함시키는 것인지 아닌지는 잘 모르겠다.)

그리고 Dynamic의 경우는 Static과는 달리 실행을 할때 찾아서 링크를 시키게 되므로 반드시 실행 파일과 같이 제공되어야 한다.

고로 배포를 목적으로 하는 프로그램이라면 반드시 /MD 옵션으로 만들어야 하고 따라서 MSVCPRT.LIB가 프로그램 작성시 링크가 된다.

그런데 프로그램이 만들어진 다음에 다른 컴퓨터에서 이것을 실행하기 위해서는 MSVCPRT.LIB가 필요한 것이 아니고, MSVCP80.DLL이 필요하다.

내가 생각할때 이 두 파일의 차이는 '개발자용'과 '사용자용'의 차이이다.

MSVCPRT.LIB는 Visual Studio를 설치해야만 제공되는 '개발자용' 라이브러리인 반면, MSVCP80.DLLMicrosoft Visual C++ 2005 Redistribution Package SP1 (x86)을 설치하면 Windows/WinSxS 폴더에 자연스럽게 설치가 되는 DLL이다. 즉, '사용자가 프로그램을 돌리기 위해서 배포되는 DLL'이다.

추가로 MSDN에서 주의를 요하는 부분은 프로그램을 작성할 때 동적으로 라이브러리를 링크하는 DLL과 동적으로 라이브러리를 링크하는 DLL 혹은 프로그램이 덩어리로 묶여서 실행될 때 발생할 수 있는 문제점을 지적하고 있다.

물론 정적으로 링크된 라이브러리가 홀로 사용된다면 아무 문제 없겠지만 DLL 간에 데이터 전송이나 호출이 발생하게 되면 링크된 라이브러리가 반드시 일치한다는 보장이 없기 때문에 문제가 될수도 있다는 것을 말하고 있다.

따라서 왠만하면 모든 것을 동적으로 링크하는게 좋다 이말이군... 업데이트하기에도 좋고, 일관성도 있고... 그렇겠군. :)

결론적으로 말하자면,

1. Visual Studio 2005는 Multi Thread로 코드를 작성하는 것만 지원한다.
2. 배포를 목적으로 한다면 반드시 /MD 옵션을 사용하라.
3. 설치할 컴퓨터에 Visual Studio가 설치되어 있지 않다면 Redistribution Package 를 다운 받아서 설치하라.
4. 되도록이면 작성하는 모든 프로그램 및 DLL은 /MD 옵션으로 통일하라.
posted by 대갈장군
prev 1 next