Windows 스레딩 : _beginthread vs _beginthreadex vs CreateThread C ++ / 단점이 무엇인지를

스레드, 시작하는 더 좋은 방법이 무엇인가 _beginthread, _beginthreadx또는 CreateThread?

나는의 장점 / 단점이 무엇인지를 결정하기 위해 노력하고있어 _beginthread, _beginthreadex하고 CreateThread. 이 모든 함수는 스레드 핸들을 새로 생성 된 스레드로 반환합니다 .CreateThread는 오류가 발생할 때 약간의 추가 정보를 제공한다는 것을 알고 있습니다 (호출하여 확인할 수 있음 GetLastError) …하지만 내가 할 때 고려해야 할 사항은 무엇입니까? 이 기능을 사용하고 있습니까?

Windows 응용 프로그램으로 작업 중이므로 크로스 플랫폼 호환성은 이미 의문의 여지가 없습니다.

나는 msdn 문서를 살펴 보았는데, 예를 들어 누군가 왜 CreateThread 대신 _beginthread를 사용하기로 결정했는지 또는 그 반대인지 이해할 수 없습니다.

건배!

업데이트 : 좋아, 모든 정보에 감사드립니다. WaitForSingleObject()사용하면 호출 할 수없는 두 곳에서 읽었 _beginthread()지만 _endthread()스레드를 호출 하면 작동하지 않아야합니까? 거래는 무엇입니까?



답변

CreateThread() 커널 수준에서 다른 제어 스레드를 작성하기위한 원시 Win32 API 호출입니다.

_beginthread()& 뒤에서 _beginthreadex()호출하는 C 런타임 라이브러리 호출입니다 CreateThread(). 일단 CreateThread()반환 되면 _beginthread/ex()추가 런타임을 처리하여 C 런타임 라이브러리를 새 스레드에서 사용 가능하고 일관성있게 만듭니다.

C ++에서는 C _beginthreadex()런타임 라이브러리 (MSVCRT * .dll / .lib)에 전혀 연결하지 않는 한 거의 확실하게 사용해야 합니다.


답변

_beginthread()와 사이에는 몇 가지 차이점이 있습니다 _beginthreadex(). (매개 변수와 동작 방식)에서 _beginthreadex()더 비슷하게 작동하도록 만들어졌습니다 CreateThread().

Drew Hall이 언급 했듯이 C / C ++ 런타임을 사용 하는 경우 런타임이 자체 스레드 초기화 (스레드 로컬 스토리지 설정 등)를 수행 할 수 있도록 대신 _beginthread()/ 를 사용해야합니다 ._beginthreadex()CreateThread()

실제로 이것은 CreateThread()코드에서 직접 사용하지 않아야 함을 의미합니다 .

차이점에 대한 MSDN 문서 _beginthread()/ _beginthreadex()자세한 내용은 매우 중요합니다. 더 중요한 것 중 하나 _beginthread()는 스레드가 종료 될 때 생성 된 스레드의 스레드 핸들 이 CRT에 의해 자동으로 닫히기 때문에 “_beginthread에 의해 생성 된 스레드가 종료되면 _beginthread의 호출자에게 리턴 된 핸들이 유효하지 않거나 다른 스레드를 가리킬 수 있습니다. “

_beginthreadex()CRT 소스에 대한 의견은 다음과 같습니다 .

Differences between _beginthread/_endthread and the "ex" versions:

1)  _beginthreadex takes the 3 extra parameters to CreateThread
  which are lacking in _beginthread():
    A) security descriptor for the new thread
    B) initial thread state (running/asleep)
    C) pointer to return ID of newly created thread

2)  The routine passed to _beginthread() must be __cdecl and has
  no return code, but the routine passed to _beginthreadex()
  must be __stdcall and returns a thread exit code.  _endthread
  likewise takes no parameter and calls ExitThread() with a
  parameter of zero, but _endthreadex() takes a parameter as
  thread exit code.

3)  _endthread implicitly closes the handle to the thread, but
  _endthreadex does not!

4)  _beginthread returns -1 for failure, _beginthreadex returns
  0 for failure (just like CreateThread).

2013 년 1 월 업데이트 :

VS 2012의 CRT에는 다음과 같은 추가 초기화 비트가 있습니다 _beginthreadex(). 프로세스가 “패키지 된 앱”인 경우 (유용한 것이 반환 된 경우 GetCurrentPackageId()) 런타임은 새로 작성된 스레드에서 MTA를 초기화합니다.


답변

일반적으로 올바른 작업은 전화 _beginthread()/_endthread()(또는 ex()변형) 를 호출하는 것입니다 . 당신이 .DLL로 CRT를 사용하는 경우 그러나 CRT 상태가 제대로 초기화와 CRT의 파괴 될 것이다는 DllMain호출 될 것입니다 DLL_THREAD_ATTACHDLL_THREAD_DETACH호출 할 때 CreateThread()ExitThread()또는 각각 반환.

DllMainCRT 의 코드는 VS의 설치 디렉토리 (VC \ crt \ src \ crtlib.c)에 있습니다.


답변

이것은 핵심 코드입니다 _beginthreadex(참조 crt\src\threadex.c).

    /*
     * Create the new thread using the parameters supplied by the caller.
     */
    if ( (thdl = (uintptr_t)
          CreateThread( (LPSECURITY_ATTRIBUTES)security,
                        stacksize,
                        _threadstartex,
                        (LPVOID)ptd,
                        createflag,
                        (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
    {
            err = GetLastError();
            goto error_return;
    }

나머지는 _beginthreadexCRT에 대한 스레드 별 데이터 구조를 초기화합니다.

_beginthread*스레드의 CRT 호출이 올바르게 작동한다는 장점 이 있습니다.


답변

C 런타임 라이브러리가 스레드의 자체 초기화를 수행하도록 _beginthread또는 _beginthreadex허용 해야합니다 . C / C ++ 프로그래머 만이 자신의 개발 환경을 사용하는 규칙을 따라야하므로이를 알아야합니다.

당신이 사용한다면 RTL이 당신을 위해 할 것이므로 _beginthread전화를 걸 필요가 없습니다 CloseHandle. 당신이 사용하는 경우 핸들을 기다릴 수없는 이유 _beginthread입니다. 또한 _beginthread시작 스레드가 유효하지 않은 스레드 핸들을 방금 시작한 스레드에 유지하면서 스레드 기능이 즉시 (빠르게) 종료되면 혼란을 초래합니다.

_beginthreadex핸들은 대기에 사용될 수 있지만에 대한 명시적인 호출이 필요합니다 CloseHandle. 이것은 대기와 함께 사용하기에 안전한 부분입니다. 완전히 무례하게 만드는 다른 문제는 항상 스레드를 일시 중단하는 것입니다. 성공, 레코드 핸들 등을 점검하십시오. 이력서 스레드. 이것은 시작 스레드가 핸들을 기록하기 전에 스레드가 종료되는 것을 방지하기 위해 필요합니다.

가장 좋은 방법은을 사용하고 _beginthreadex, 일시 중지를 시작한 다음 기록 핸들 후 재개하고, 핸들 대기가 정상 CloseHandle입니다.


답변

CreateThread()코드에서 CRT 함수를 사용할 때 메모리 누수가 발생했습니다. _beginthreadex()와 동일한 매개 변수를 CreateThread()가지며보다 다재다능합니다 _beginthread(). 을 사용하는 것이 좋습니다 _beginthreadex().


답변

업데이트 된 질문과 관련하여 : “또한 WaitForSingleObject()사용할 경우 호출 할 수없는 몇 곳에서 읽었 _beginthread()지만 _endthread()스레드를 호출 하면 작동하지 않아야합니까?”

일반적으로 스레드 핸들 WaitForSingleObject()(또는 객체 핸들을 기다리는 다른 API)에 스레드 핸들을 전달 하여 스레드가 완료 될 때까지 차단할 수 있습니다. 그러나에 의해 작성된 스레드 핸들 은 호출 _beginthread()될 때 닫힙니다 _endthread()(스레드 프로 시저가 리턴 될 때 런타임에 명시 적으로 수행되거나 내재적으로 수행 될 수 있음).

이 문제는 다음 문서에 나와 있습니다 WaitForSingleObject().

대기가 여전히 보류중인 동안이 핸들이 닫히면 함수의 동작이 정의되지 않습니다.