134 votes

Windows filetage: _beginthread vs _beginthreadex vs CreateThread C++

Ce est une meilleure façon de démarrer un thread?

Je suis en train d'essayer de déterminer quels sont les avantages/inconvénients de _beginthread, _beginthreadex et CreateThread. Toutes ces fonctions renvoient un fil de la poignée pour un nouveau thread, je sais déjà que CreateThread fournit un peu plus d'informations lorsqu'une erreur se produit (il peut être vérifié par l'appel de GetLastError)... mais ce sont des choses que je devrais envisager quand je suis à l'aide de ces fonctions?

Je travaille avec une application windows, de sorte que la croix-plate-forme de compilation est déjà hors de question.

Je suis passé par la documentation msdn et j'ai juste ne peut pas comprendre, par exemple, pourquoi quelqu'un pourrait décider de les utiliser _beginthread au lieu de CreateThread ou vice versa.

Cheers!

Mise à jour: OK, merci pour toutes ces infos, j'ai aussi lu dans un couple des endroits que je ne peux pas appeler WaitForSingleObject() si j'ai utilisé _beginthread(), mais si je l'appelle _endthread() dans le thread ne faut pas que le travail? Qu'est-ce qu'il y a?

99voto

Drew Hall Points 15917

CreateThread() est un brut de l'API Win32 appel à la création d'un autre thread de contrôle au niveau du noyau.

_beginthread() & _beginthreadex() C runtime library appels appel en CreateThread() derrière les coulisses. Une fois CreateThread() a retourné, _beginthread/ex() prend soin de supplémentaires de tenue de compte pour faire de la bibliothèque runtime C utilisable et compatible dans le nouveau thread.

En C++, vous devriez presque certainement utiliser _beginthreadex() , à moins que vous ne serez pas en les reliant à la bibliothèque runtime C (aka MSVCRT*.dll/.lib).

38voto

Michael Burr Points 181287

Il existe plusieurs différences entre _beginthread() et _beginthreadex(). _beginthreadex() a été faite à agir plus comme CreateThread() (dans les deux paramètres et comment il se comporte).

Comme Drew Salle de mentions, si vous utilisez le C/C++ runtime, vous devez utiliser _beginthread()/_beginthreadex() au lieu de CreateThread() , de sorte que l'exécution ait une chance de réaliser son propre thread d'initialisation (mise en place de thread local storage, etc.).

Dans la pratique, cela signifie qu' CreateThread() doit à peu près jamais être utilisé directement par votre code.

La MSDN documents pour l' _beginthread()/_beginthreadex() ont un peu de détail sur les différences - l'un des plus important est que, depuis le fil de la poignée pour un thread créé par _beingthread() se ferme automatiquement par le CRT lorsque le thread s'arrête, "si le thread généré par _beginthread quitte rapidement, le handle retourné à l'appelant de _beginthread peut-être pas valide ou, pire, point à un autre thread".

Voici ce que les commentaires de l' _beginthreadex() dans la source CRT ont à dire:

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).

Mise À Jour De Janvier 2013:

Le CRT pour VS 2012 a un bit supplémentaire de l'initialisation effectuée en _beginthreadex(): si le processus est un "emballé application" (si quelque chose d'utile est retourné à partir de GetCurrentPackageId()) l'exécution d'initialiser la MTA sur le nouveau thread.

24voto

MSN Points 30386

En général, la bonne chose à faire est d'appeler _beginthread()/_endthread() (ou ex() variantes). Toutefois, si vous utilisez le CRT comme une .dll, le CRT état d'être correctement initialisé et détruits comme les tubes DllMain seront appelés DLL_THREAD_ATTACH et DLL_THREAD_DETACH lors de l'appel d' CreateThread() et ExitThread() ou de reprendre, respectivement.

L' DllMain code pour le CRT peut être trouvé dans le répertoire d'installation pour VS en vertu de CR\crt\src\crtlib.c.

17voto

Constantin Points 12185

C'est le code à la base de l' _beginthreadex (voir 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;
    }

Le reste de l' _beginthreadex initialise par thread structure de données pour les CRT.

L'avantage de l'utilisation d' _beginthread* , c'est que votre CRT appels à partir du fil fonctionne correctement.

13voto

jarcher7 Points 71

Voici la réponse réelle. Il ya une certaine mauvaise information dans d'autres commentaires.

Vous devez utiliser _beginthread ou _beginthreadex pour permettre à la bibliothèque d'exécution C pour faire son propre initialiation du fil. Seuls les programmeurs C/C++ besoin de savoir ce qu'ils doivent maintenant les règles de l'utilisation de leur propre développement envrionnement.

Si vous utilisez _beginthread vous n'avez pas besoin d'appeler CloseHandle que le RTL fera pour vous. C'est pourquoi vous ne pouvez pas attendre sur la poignée si vous avez utilisé _beginthread. Aussi _beginthread conduit à la confusion si la fonction de thread quitte immédiatement (rapidement) que le lancement de fil de mon être à gauche tenant une défaillance de thead poignée pour le thread qu'il vient de lancer.

_beginthreadex les poignées peuvent être utilisés pour attendre, mais aussi un appel explicite à CloseHandle. C'est en partie ce qui les rend sans danger pour l'utilisation à attendre. Il y a un autre problème pour le faire complètement infaillible est de toujours commencer le fil suspendu. Vérification de la réussite, de l'enregistrement de la poignée etc. Le résumé fil. Cela est nécessaire pour éviter un fil de résiliation avant le lancement du thread peut enregistrer sa poignée.

La meilleure pratique consiste à utiliser _beginthreadex, commencer suspendu, puis le reprendre après l'enregistrement de la poignée, attendre sur la poignée est OK, CloseHandle doit être appelée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X