반응형

http://blog.naver.com/kki2406/80041209326

_beginthreadex와 _endthreadex 함수는 API 함수가 아니라 C Library 함수이다.

 

이 함수들에 관한 사용법을 알아보자...

 

API 함수와 매우 유사하다.

 

#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <tchar.h>

 

unsigned counter;

 

unsigned __stdcall SecondThreadFunc( void *pArg )
{
 _tprintf(_T(" * In second thread... \n") );
 while ( counter < 1000000 ) counter ++;
 _endthreadex(0);
 return 0;
}

 

int main()
{
 HANDLE hThread;
 unsigned threadID;

 

 _tprintf( _T(" * Creating second thread... \n ") );
 hThread = (HANDLE) _beginthreadex(NULL, 0, SecondThreadFunc, NULL, 0, &threadID );
 
 WaitForSingleObject( hThread, INFINITE );

 _tprintf( _T(" * Counter should be 1000000; it is -> %d\n"), counter );

 CloseHandle( hThread );

 

 return 0;
}

 

 

SecondThreadFunc의 원형은 API의 CreateThread로 부르는 함수(Createthread 함수의 세번째 인자)의 원형과 동일하다.

 

 

이 _beginthreadex 함수는 내부적으로 CreateThread 함수를 호출하고 있다.

 

이를 보고 싶다면 MS사에서 제공하는 코드를 직접 보면 될 것이다.

 

이 코드 파일은 첨부토록 하겠다. _beginthreadex 함수를 찾아보면 알 것이다.

 

또한, thread 생성과 파괴시 다음과 같은 함수들이 존재한다.

 

학습 : CreateThread), ExitThread()
C Library + API : _beginthreadex(), _endthreadex();
MFC : AfxBeginThread(), AfxEndThread();

 

 

 


 

http://blog.naver.com/limsk112/70107328764

 

 

CreateThread 함수는 Win32 API 에서 제공되는 함수고

_beginthread,  _beginthreadex 함수는 C / C++ Runtime-Library 에서 제공되는 함수다.

 

_beginthread 함수는  이 함수로 새로운 쓰레드를 생성하고 난 후 바로 ::CloseHandle( ) 함수를 호출해서 생성한 쓰레드의 핸들을 닫아 버려서 생성한 쓰레드 오브젝트와의 통신을 할 수가 없다. 핸들을 바로 닫아버리는 이유는 Win32의 상세함을 숨기기 위함인데 결국 버그가 되어 버린 함수이다.

 

 이를 고안해서 새로 탄생한 함수가 바로 _beginthreadex 함수이다.

_beginthreadex 는 내부적으로 새로 생성한 쓰레드의 핸들을 닫지 않기 때문에 명시적으로 ::CloseHandle( ) 함수를 호출하여 쓰레드의 핸들을 수동으로 닫아 주어야 한다.

_beginthreadex 의 리턴값은 새로 생성된 쓰레드의 핸들값이다. 하지만 자료형이 정확히 일치하지 않기 때문에 적절하게 형변환을 해줘야 한다.

 

 

_beginthread 함수와 짝을 이루는 것이 _endthread 함수인데, 생성한 쓰레드가 종료되면, 이 함수가 자동 호출 되어진다. 따라서 이 함수는 명시하지 않으며, 명시를 해주면 에러가 난다.

 

_beginthreadex 함수와 짝을 이루는 것은 _endthreadex 함수다. 이 함수는 생성한 쓰레드가 종료되면, 역시 이 함수가 자동 호출되어 진다. 따라서 이 함수는 명시하지 않아도 되지만, 명시를 해도 _endthread 함수처럼 에러가 나는건 아니다.

 


[더 자세한 설명]- 아래까지 보는게 좋다

 

 

http://blog.naver.com/drags99/150032023121

 

두 함수는 모두 스래드를 생성할 때 호출하는 함수이다.

 

이 두 함수는 겉으로 보기엔 동일한 기능을 하지만 차이점이 있어서 이를 알고 넘어가야 한다.

MSDN을 보면 _beginthread 와 _beginthreadex 를 사용하면 스래드에 여러 인수를 전달할 수 있습니다라고 되어있다이러한 이유로 CreateThread 보다는 위 두 함수를 많이 이용한다.

위 두 함수 중에도 개인적으로는 _beginthreadex 함수를 주로 이용하고 있다.

위 두 함수의 차이점을 비교해 보면

함수 호출 규약이 _beginthread 함수는 __cdecl 이고, _beginthreadex 함수는 __stdcall 이다.

함수 호출 규약에 따라 내부적으로 인자 값들을 스택에 저장할 때 순서가 달라진다이러한 부분은 코딩을 하는 부분에서는 크게 신경 쓰지 않아도 되는 부분이다.

또 다른 차이점은 각각의 함수는 _endthread, __endthreadex 라는 함수와 같이 이용된다는 점이다딱 봐도 뒤에 ex 가 붙은 함수와 안 붙은 함수가 세트로 사용된다는 걸 쉽게 이해할 수 있을 것이다.

또 다른 차이점은 return Value 값이다.

_beginthread 함수의 경우 성공일 때 0, 실패일 때 -1을 리턴 하지만, _beginthreadex 함수는 실패일 때 0(NULL), 성공일 때 -1이 아닌 값을 리턴 한다.

_beginthread 함수는 성공과 실패를 구분하지만 _beginthreadex 함수는 실제 HANDLE 을 리턴하기 때문에 GetExitCodeThread 함수 호출 등이 가능하게 된다.

두 함수를 호출하는데 있어서 인자 값도 차이가 난다.

_beginthreadex 함수에서 initflag 값을 이용해 스래드가 생성되는 시점에서 스래드의 상태를 설정할 수 있다.

threadaddr 은 32bit 포인터 값으로 스래드의 주소 값을 반환 받을 수 있다.

Security 인자를 이용해 자식 프로세스에서 이 함수에서 반환된 스래드의 핸들을 상속받아서 사용할 수 있는지 유무를 결정할 수 있다.

위와 같은 차이가 나지만 대부분은 _beginthreadex 함수를 많이 이용할 것이다.

하지만 _beginthreadex 함수를 이용해야 하는 아주 결정적인 이유가 하나 더 있다.

Ansi 표준 라이브러리 함수를 호출할 경우 _beginthread 함수를 이용해 생성된 스래드 에서는 동기화 이유 때문에 안정성을 보장받지 못하게 되지만 _beginthreadex 함수를 이용할 경우 스래드별로 내부적으로 별도의 메모리 공간을 할당하기 때문에 동기화와 관련돼 안정성을 보장받을 수 있게 된다이렇게 스래드 생성시 할당된 별도의 메모리 공간을 해제하기 위해서 _endthreadex 함수와 짝을 이뤄서 이용하게 되는 것이다.

컴파일러에 따라 다르겠지만 .Net 에서는 멀티스래드에 안정적인 라이브러리를 제공하고 있기 때문에 별도의 선언이나 조작 없이도 안정적인 라이브러리를 이용할 수 있다고 한다.(아직까지는 별 문제 없이 잘 쓰고 있다.)

만약 _beginthreadex 함수로 스래드를 생성하고 _endthread 함수를 이용해 스래드를 종료하게 된다면 스래드 생성시에 할당된 메모리가 반환되지 않기 때문에 이렇게 스래드를 이용할 수 없다.

하지만 스래드를 생성할 때 인자로 넘긴 함수 포인터에서 return 을 이용해 스래드를 종료하게 되면 별도의 _endthreadex 함수를 호출하지 않아도 생성시에 할당된 메모리가 반환되기 때문에 return 을 이용하면 이 부분은 별로 걱정할 필요 없다.

스래드 종료 시 반환된 값은 내부에 생성된 스래드 커널에 저장되고, GetExitCodeThread 함수를 이용해 받아올 수 있다.

하지만 위 함수를 호출하기 전에 CloseHandle 함수를 이용해 스래드 핸들을 종료시킨다면 내부에 생성된 스래드 커널이 삭제되기 때문에 반환 값을 받을 수 없게 된다.

스래드의 반환 값을 이용할 필요가 있을 경우 GetExitCodeThread 함수를 이용해서 반환 값을 받아온 후에 CloseHandle 함수를 호출해 줘야 한다.

추가로 한가지 더 얘기 하면 CloseHandle 을 이용해서 함수 호출 시 반환된 스래드의 핸들을 종료시키게 되면 내부적으로 스래드 커널에 UC가 줄어들게 되 스래드가 종료되는 시점에서 스래드 커널도 바로 종료될 수 있다이 부분은 커널과 핸들러에 관한 내용을 미리 알고 있어야 해서 간단히 설명한다.

.. 두 함수를 비교하다 보니 결론적으로 코딩할때는 _beginthreadex 함수만 이용하게 된다.

솔직히 _endthreadex 함수도 거의 사용하지 않는다그냥 함수 내에서 return 을 이용해 스래드를 종료하고 있다.

 

반응형

+ Recent posts