Filetage Windows: _beginthread vs _beginthreadex vs CreateThread C ++

133

Quelle est la meilleure façon de démarrer un fil _beginthread, _beginthreadxou CreateThread?

J'essaie de déterminer quels sont les avantages / inconvénients de _beginthread, _beginthreadexet CreateThread. Toutes ces fonctions renvoient un descripteur de thread à un thread nouvellement créé, je sais déjà que CreateThread fournit un peu d'informations supplémentaires lorsqu'une erreur se produit (cela peut être vérifié en appelant GetLastError) ... mais que dois-je prendre en compte lorsque je ' m en utilisant ces fonctions?

Je travaille avec une application Windows, donc la compatibilité multiplateforme est déjà hors de question.

J'ai parcouru la documentation msdn et je ne peux tout simplement pas comprendre, par exemple, pourquoi quelqu'un déciderait d'utiliser _beginthread au lieu de CreateThread ou vice versa.

À votre santé!

Mise à jour: OK, merci pour toutes les informations, j'ai également lu dans quelques endroits que je ne peux pas appeler WaitForSingleObject()si j'ai utilisé _beginthread(), mais si j'appelle _endthread()dans le fil de discussion, cela ne devrait-il pas fonctionner? Quel est le problème là-bas?

Kiril
la source
2
Voici une analyse de ce que fait _beginthreadex () pour les programmeurs C / C ++ que j'ai trouvé à partir d'un lien sur le site Web d'Eli Bendersky. Cela provient d'une question-réponse sur l'utilisation ou non de CreateThread (). microsoft.com/msj/0799/win32/win320799.aspx
Richard Chambers

Réponses:

96

CreateThread() est un appel API Win32 brut pour créer un autre thread de contrôle au niveau du noyau.

_beginthread()& _beginthreadex()sont des appels de bibliothèque d'exécution C qui appellent CreateThread()dans les coulisses. Une fois CreateThread()retourné, _beginthread/ex()s'occupe de la comptabilité supplémentaire pour rendre la bibliothèque d'exécution C utilisable et cohérente dans le nouveau thread.

En C ++, vous devriez certainement utiliser à _beginthreadex()moins que vous ne fassiez pas du tout de lien vers la bibliothèque d'exécution C (aka MSVCRT * .dll / .lib).

Drew Hall
la source
39
Ce n'est plus aussi vrai qu'auparavant. Le CRT fonctionnera correctement dans un thread créé par CreateThread () à l'exception de la fonction signal (). Il y aura une petite fuite de mémoire (~ 80 octets) pour chaque thread créé avec CreateThread () qui utilise le CRT, mais il fonctionnera correctement. Voir pour plus d'informations: support.microsoft.com/default.aspx/kb/104641
John Dibling
1
@John: En fait, ce bogue s'applique uniquement jusqu'à MSVC ++ 6.0
bobobobo
5
@bobobobo: Bonne question. Je ne peux que spéculer que MS avait initialement prévu que les _beginroutines soient des appels internes et qu'elle CreateThreadétait censée être la fonction API que tout le monde appellerait. Une autre explication potentielle est que MS a une longue et glorieuse histoire d'ignorance de la norme et de très mauvaises décisions concernant la dénomination des choses.
John Dibling
15
Les _beginfonctions commencent par un trait de soulignement car Microsoft a commencé à suivre de plus près la norme. Dans l'environnement d'exécution C, les noms comportant un trait de soulignement sont réservés pour l'implémentation (et l'implémentation peut les documenter pour une utilisation par l'utilisateur final, comme avec ceux-ci). beginthreadex()est un nom que l'utilisateur peut utiliser. Si le moteur d'exécution C l'utilisait, il pourrait entrer en conflit avec un symbole d'utilisateur final que l'utilisateur avait le droit légitime de s'attendre à utiliser. Notez que les API Win32 ne font pas partie du runtime C et qu'elles utilisent l'espace de noms de l'utilisateur.
Michael Burr
2
@Lothar: Il existe des différences entre l'appel d'API Win32 CreateThreadet les appels CRT _beginthread/ex, et lors de l'appel du CRT sur un thread, il doit toujours être créé avec _beginthread/ex. Il se peut qu'il n'y ait plus de fuites de mémoire, sinon. Mais vous n'obtiendrez sûrement pas votre environnement en virgule flottante correctement initialisé lors d'un appel CreateThread, par exemple. Il y a plus : "Si un thread créé à l'aide de CreateThread appelle le CRT, le CRT peut terminer le processus dans des conditions de mémoire insuffisante."
IInspectable
37

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

Comme Drew Hall le mentionne, si vous utilisez le runtime C / C ++, vous devez utiliser _beginthread()/ _beginthreadex()au lieu de CreateThread()pour que le runtime ait une chance d'effectuer sa propre initialisation de thread (configuration du stockage local des threads, etc.).

En pratique, cela signifie que cela CreateThread()ne devrait pratiquement jamais être utilisé directement par votre code.

Les documents MSDN pour _beginthread()/ _beginthreadex()ont pas mal de détails sur les différences - l'une des plus importantes est que puisque le handle de thread pour un thread créé par _beginthread()se ferme automatiquement par le CRT lorsque le thread se termine, "si le thread généré par _beginthread se termine rapidement, le handle retourné à l'appelant de _beginthread peut être invalide ou, pire, pointer vers un autre thread ".

Voici ce que _beginthreadex()disent les commentaires dans la source 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).

Mise à jour de janvier 2013:

Le CRT pour VS 2012 a un bit supplémentaire d'initialisation effectué dans _beginthreadex(): si le processus est une "application packagée" (si quelque chose d'utile est renvoyé GetCurrentPackageId()), le runtime initialisera le MTA sur le thread nouvellement créé.

Michael Burr
la source
3
Il y a des moments appropriés où CreateThread () est justifié, mais honnêtement, vous devez vraiment faire tout votre possible pour le faire. Nous parlons d'un manque complet de tout ce qui est portable et d'écrire une DLL ou une application API exclusivement WIN32. Y compris aucun appel C-runtime. Même l'utilisation de STL est limitée dans la mesure où vous devez fournir des allocateurs personnalisés pour utiliser les fonctions de gestion de la mémoire WIN32. La configuration pour faire cela avec Developer Studio est un travail en soi, mais pour une bibliothèque uniquement WIN32 avec le plus petit encombrement possible, cela peut être fait. Mais oui, ce n'est pas très probable pour presque tous, mais pour quelques privilégiés.
WhozCraig
1
@WhozCraig: Il y a des limitations plus sévères lors de l'omission du CRT. Les plus importants étant: pas de prise en charge des entiers 64 bits, pas de prise en charge de la virgule flottante et - le plus radicalement - pas de gestion des exceptions. Cela signifie vraiment pas de gestion des exceptions - du tout . Pas même d'exceptions SEH. Ceci est particulièrement difficile à compenser, et les chances d'appeler CreateThreadla bonne chose sont de moins en moins minces.
IInspectable le
@MichaelBurr: Vous voudrez peut-être mettre à jour votre réponse pour VC ++ 2015 .
user541686
@Mehrdad: Quels changements trouvez-vous particulièrement intéressant de mentionner?
IInspectable le
J'ai trouvé que DisableThreadLibraryCalls n'a aucun effet sur les threads créés avec CreateThread, mais désactive les threads créés avec _beginthread ou _beginthreadex.
SPlatten le
23

En général, la bonne chose à faire est d'appeler _beginthread()/_endthread()(ou les ex()variantes). Toutefois, si vous utilisez le CRT en tant que .dll, l'état CRT sera correctement initialisé et détruit comme le CRT DllMainsera appelé avec DLL_THREAD_ATTACHet DLL_THREAD_DETACHlors de l'appel CreateThread()et ExitThread()ou du retour, respectivement.

Le DllMaincode du CRT se trouve dans le répertoire d'installation de VS sous VC \ crt \ src \ crtlib.c.

MSN
la source
Excellent point de départ. Avec un peu de débogage, on peut montrer que __CRTDLL_INIT est appelé même pour un CRT lié statiquement. Callstack le init est appelé à partir de _LdrpCallInitRoutine @ 16 (), je ne sais pas exactement par quel mécanisme. Cela signifie qu'avec le CRT récent, toute l'initialisation / désinitialisation est effectuée correctement à l'exception de la gestion du signal, qui est toujours effectuée dans la fonction d'assistance _threadstartex appelée depuis beginthread, mais pas depuis CreateThread. Peut-être pourriez-vous ajouter ceci dans la réponse et je vais attribuer la prime?
Suma
Prime attribuée, car cela semble le plus utile. Pourtant, la réponse mériterait peut-être d'être mise à jour. Si vous ne pouvez pas le faire, je pourrais y revenir dans quelques jours.
Suma
1
@MSN: Veuillez noter que CreateThread est toujours mauvais dans une DLL, si vous liez contre le CRT statique et avez appelé DisableThreadLibraryCalls qui désactive les appels pour DLL_THREAD_DETACH. Ensuite, vous obtiendrez des fuites de mémoire. Ceci est documenté ici dans mon article KB: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach
17

C'est le code au cœur de _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 _beginthreadexinitialise la structure de données par thread pour CRT.

L'avantage de l'utilisation _beginthread*est que vos appels CRT à partir de thread fonctionneront correctement.

Constantin
la source
12

Vous devez utiliser _beginthreadou _beginthreadexpour permettre à la bibliothèque d'exécution C de faire sa propre initialisation du thread. Seuls les programmeurs C / C ++ ont besoin de le savoir car ils devraient désormais connaître les règles d'utilisation de leur propre environnement de développement.

Si vous utilisez, _beginthreadvous n'avez pas besoin d'appeler CloseHandlecomme le RTL le fera pour vous. C'est pourquoi vous ne pouvez pas attendre sur la poignée si vous avez utilisé _beginthread. Conduit également _beginthreadà la confusion si la fonction de thread se termine immédiatement (rapidement) car le thread de lancement peut être laissé avec une poignée de thread non valide pour le thread qu'il vient de lancer.

_beginthreadexles handles peuvent être utilisés pour wait mais nécessitent également un appel explicite à CloseHandle. Cela fait partie de ce qui les rend sûrs pour une utilisation avec attente. Il y a un autre problème pour le rendre complètement infaillible est de toujours démarrer le thread suspendu. Vérifiez le succès, enregistrez la poignée, etc. Cela est nécessaire pour empêcher un thread de se terminer avant que le thread de lancement puisse enregistrer son handle.

La meilleure pratique consiste à utiliser _beginthreadex, démarrer suspendu puis reprendre après l'enregistrement de la poignée, attendre que la poignée est OK, CloseHandledoit être appelée.

jarcher7
la source
8

CreateThread()utilisé pour avoir des fuites de mémoire lorsque vous utilisez des fonctions CRT dans votre code. _beginthreadex()a les mêmes paramètres que CreateThread()et il est plus polyvalent que _beginthread(). Je vous recommande donc d'utiliser _beginthreadex().

Piéton indiscipliné
la source
2
Article de 1999, peut depuis avoir été corrigé
bobobobo
1
Cet article de 2005 confirme toujours qu'il y a un problème.
Jaywalker
2
Oui, cela s'applique uniquement à MSVC ++ 6.0 Service Pack 5 et versions antérieures. (voir "S'applique à" liste déroulante extensible). Ce n'est pas un problème aujourd'hui si vous utilisez VC7 ou supérieur.
bobobobo
1
C'est toujours un problème, si vous liez contre le CRT statique! C'est également toujours un problème si vous appelez DisableThreadLibraryCalls dans une DLL qui est liée statiquement; voir mon article KB: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach
2
Vous avez déformé les informations: CreateThreadne perd jamais de mémoire. C'est plutôt le CRT qui le fait, lorsqu'il est appelé à partir d'un thread qui n'a pas été correctement initialisé.
IInspectable le
6

En ce qui concerne votre question mise à jour: "J'ai également lu dans quelques endroits que je ne peux pas appeler WaitForSingleObject()si j'ai utilisé _beginthread(), mais si j'appelle _endthread()dans le fil de discussion, cela ne devrait-il pas fonctionner?"

En général, vous pouvez passer un handle de thread à WaitForSingleObject()(ou à d'autres API qui attendent sur les handles d'objet) pour bloquer jusqu'à ce que le thread soit terminé. Mais le handle de thread créé par _beginthread()est fermé lorsqu'il _endthread()est appelé (ce qui peut être fait explicitement ou est fait implicitement par le moment de l'exécution lorsque la procédure de thread retourne).

Le problème est signalé dans la documentation pour WaitForSingleObject():

Si ce handle est fermé alors que l'attente est toujours en attente, le comportement de la fonction n'est pas défini.

Michael Burr
la source
5

En regardant les signatures de fonction, CreateThreadest presque identique à _beginthreadex.

_beginthread,_beginthreadx vsCreateThread

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

Les remarques ici indiquent que vous _beginthreadpouvez utiliser la convention soit __cdeclou __clrcallappeler comme point de départ, et _beginthreadexpeut utiliser soit __stdcallou __clrcallcomme point de départ.

Je pense que tous les commentaires des gens sur les fuites de mémoire datent de CreateThreadplus d'une décennie et devraient probablement être ignorés.

Fait intéressant, les deux _beginthread*fonctions appellent CreateThreadsous le capot, C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\srcsur ma machine.

// From ~line 180 of beginthreadex.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;
}
bobobobo
la source
2
Commentez, pourquoi vous ne devriez pas appeler CreateThread et mélanger les appels CRT sur ce thread (certainement pas une décennie, et ne doit certainement pas être ignoré) : "Si un thread créé à l'aide de CreateThread appelle le CRT, le CRT peut terminer le processus en conditions de mémoire insuffisante. "
IInspectable le
3

beginthreadexvous donne un fil HANDLEà utiliser dans WaitForSingleObjectet vos amis. beginthreadpas. N'oubliez pas de CloseHandle()quand vous avez terminé. La vraie réponse serait d'utiliser boost::threadou bientôt la classe de thread de C ++ 09.

MD XF
la source
La description de msdn indique que "En cas de succès, chacune de ces fonctions renvoie un handle vers le thread nouvellement créé;" faisant référence à _beginthread () et _beginthreadex () ...
Kiril
@Kiril: mais la documentation continue en disant que _beginthread ferme la poignée pour vous, ce qui signifie que vous ne pouvez pas l'utiliser si le fil se termine rapidement ...
Roger Lipscombe
2

Par rapport à _beginthread, avec _beginthreadexvous pouvez:

  1. Spécifiez les attributs de sécurité.
  2. Démarrez un thread à l'état suspendu.
  3. Vous pouvez obtenir l'ID de thread qui peut être utilisé avec OpenThread.
  4. Le descripteur de thread renvoyé est garanti valide si l'appel a réussi. Là, vous devez fermer la poignée avec CloseHandle.
  5. Le descripteur de thread renvoyé peut être utilisé avec les API de synchronisation.

Le _beginthreadexressemble beaucoup CreateThread, mais le premier est une implémentation CRT et le second un appel d'API Windows. La documentation de CreateThread contient la recommandation suivante:

Un thread dans un exécutable qui appelle la bibliothèque d'exécution C (CRT) doit utiliser les fonctions _beginthreadexet _endthreadexpour la gestion des threads plutôt que CreateThreadet ExitThread; cela nécessite l'utilisation de la version multithread du CRT. Si un thread créé à l'aide d' CreateThreadappels le CRT, le CRT peut terminer le processus dans des conditions de mémoire insuffisante.

Vishal
la source
Selon la spécification de l'API, les puces 3-5 ne sont pas uniques à _beginthreadex. Vous pouvez convertir le uintptr_tretour des deux fonctions en HANDLE.
Andon M. Coleman
Oui, vous avez raison en théorie. En pratique, la différence est que _beginthreadferme la poignée en sortie. Vous ne pouvez donc pas utiliser de manière fiable le handle avec les API de synchronisation ou pour obtenir l'ID de thread jusqu'à ce que et à moins que vous n'utilisiez un autre moyen de synchroniser et de dupliquer le handle. Mais alors il y a le _beginthreadexfaire pour vous.
Vishal
2

CreateThread()une fois était un non-non parce que le CRT serait incorrectement initialisé / nettoyé. Mais c'est maintenant de l'histoire: on peut maintenant (en utilisant VS2010 et probablement quelques versions en arrière) appeler CreateThread()sans casser le CRT.

Voici la confirmation officielle de MS . Il énonce une exception:

En fait, la seule fonction qui ne doit pas être utilisée dans un thread créé avec CreateThread()est la signal()fonction.

Cependant, du point de vue de la cohérence, je préfère personnellement continuer à utiliser _beginthreadex().

Serge Wautier
la source
Bien que je suppose que cela est vrai, pouvez-vous fournir des preuves faisant autorité - soit en établissant un lien vers la documentation MS, soit en analysant les sources CRT _beginthreadex / _endthreadex?
Suma
@Suma, je suppose que j'ai ajouté le lien MS pendant que vous tapiez votre commentaire ;-)
Serge Wautier
Le document que vous liez ne semble pas confirmer: "Cependant, selon les fonctions CRT appelées, il peut y avoir une petite fuite de mémoire lorsque les threads sont terminés.". Cela signifie que ce n'est plus un non-non grand et général, mais toujours un non-non si vous créez fréquemment des threads et utilisez ces fonctions. Cependant, le document date de 2005 et ne peut donc pas aborder l'état récent de la question.
Suma
1
Hmm ... bien que cela puisse dépendre du cas d'utilisation, une fonction laissant une fuite de mémoire, quelle que soit la taille, je considérerais un non-non ... - en particulier s'il existe une alternative sans fuite!
alk
"On peut maintenant appeler CreateThread () sans casser le CRT." - Malheureusement, ce n'est pas vrai et ne l'a jamais été. De CreateThread : «Un thread dans un exécutable qui appelle la bibliothèque d'exécution C (CRT) doit utiliser les fonctions _beginthreadex et _endthreadex pour la gestion des threads [...] Si un thread créé à l'aide de CreateThread appelle le CRT, le CRT peut mettre fin au processus dans des conditions de mémoire insuffisante. "
IInspectable le
2

CreateThread()est un appel d'API Windows indépendant du langage. Il crée simplement un objet OS - thread et renvoie HANDLE à ce thread. Toutes les applications Windows utilisent cet appel pour créer des threads. Tous les langages évitent les appels d'API directs pour des raisons évidentes: 1. Vous ne voulez pas que votre code soit spécifique au système d'exploitation 2. Vous devez faire quelques tâches ménagères avant d'appeler API: convertir les paramètres et les résultats, allouer un stockage temporaire, etc.

_beginthreadex()est un wrapper C CreateThread()qui tient compte du C spécifique. Il permet aux C f-ns à thread unique d'origine de travailler dans un environnement multithread en allouant un stockage spécifique au thread.

Si vous n'utilisez pas CRT, vous ne pouvez pas éviter un appel direct à CreateThread(). Si vous utilisez CRT, vous devez utiliser _beginthreadex()ou certaines chaînes CRT f-ns peuvent ne pas fonctionner correctement avant VC2005.

SKV
la source
1

CreateThread()est l'appel système direct. Il est implémenté sur Kernel32.dlllequel, très probablement, votre application sera déjà liée pour d'autres raisons. Il est toujours disponible dans les systèmes Windows modernes.

_beginthread()et _beginthreadex()sont des fonctions wrapper dans Microsoft C Runtime ( msvcrt.dll). Les différences entre les deux appels sont indiquées dans la documentation. Il est donc disponible lorsque le Microsoft C Runtime est disponible, ou si votre application est liée statiquement à celui-ci. Vous serez probablement lié à cette bibliothèque, à moins que vous ne codiez dans l'API Windows pure (comme je le fais souvent personnellement).

Votre question est cohérente et en fait récurrente. Comme de nombreuses API, il existe des fonctionnalités dupliquées et ambiguës dans l'API Windows avec lesquelles nous devons faire face. Pire encore, la documentation ne clarifie pas le problème. Je suppose que la _beginthread()famille de fonctions a été créée pour une meilleure intégration avec d'autres fonctionnalités C standard, telles que la manipulation de errno. _beginthread()s'intègre ainsi mieux avec le runtime C.

Malgré cela, à moins que vous n'ayez de bonnes raisons d'utiliser _beginthread()ou _beginthreadex(), vous devriez utiliser CreateThread(), principalement parce que vous pourriez avoir une dépendance de bibliothèque en moins dans votre exécutable final (et pour MS CRT, cela a un peu d'importance). Vous n'avez pas non plus de code d'encapsulation autour de l'appel, bien que cet effet soit négligeable. En d'autres termes, je pense que la principale raison de s'en tenir CreateThread()est qu'il n'y a pas de bonne raison d'utiliser _beginthreadex()pour commencer. Les fonctionnalités sont exactement, ou presque, les mêmes.

Une bonne raison d'utiliser _beginthread() serait (car cela semble être faux) que les objets C ++ seraient correctement déroulés / détruits s'ils _endthread()étaient appelés.

Alecov
la source
Il n'y a pas d' appels de fonction ambiguë du tout . CreateThreadest l'appel de l'API Windows pour créer un thread. Si vous utilisez le CRT (parce que vous programmez en C ou C ++), vous devez créer des threads en utilisant les _beginthread[ex]appels du CRT (qui appellent CreateThreaden plus d'effectuer l'initialisation CRT nécessaire). Différence la plus importante entre _beginthreadet l'ancienne variante: la première conserve la propriété du descripteur de thread natif, tandis que la seconde en transmet la propriété à l'appelant.
IInspectable le
Nitpick: msvcrt.dlln'est pas la DLL d'exécution C! Voir blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273
Govind Parmar
0

Les autres réponses n'abordent pas les implications de l'appel d'une fonction d'exécution C qui encapsule une fonction API Win32. Ceci est important lors de l'examen du comportement de verrouillage du chargeur DLL.

Que ce soit ou non _beginthread{ex}une gestion spéciale de la mémoire thread / fibre C Runtime comme le discutent les autres réponses, elle est implémentée dans (en supposant une liaison dynamique avec le run-time C) une DLL que les processus n'ont peut-être pas encore chargée.

Il n'est pas sûr d'appeler _beginthread*depuis DllMain. J'ai testé cela en écrivant une DLL chargée à l'aide de la fonction Windows "AppInit_DLLs". L'appel _beginthreadex (...)au lieu de CreateThread (...)fait que BEAUCOUP de parties importantes de Windows cessent de fonctionner pendant le démarrage, car les DllMainblocages de point d'entrée attendent que le verrou du chargeur soit libéré afin d'effectuer certaines tâches d'initialisation.

Incidemment, c'est aussi pourquoi kernel32.dll a beaucoup de fonctions de chaîne qui se chevauchent que le run-time C fait également - utilisez celles de DllMainpour éviter le même genre de situation.

Andon M. Coleman
la source
0

Si vous lisez le livre Debugging Windows Application From Jeffrey Richter, il explique que presque dans tous les cas, vous devez appeler _beginthreadexau lieu d'appeler CreateThread. _beginthreadest juste un wrapper simplifié _beginthreadex.

_beginthreadexinitialise certains composants internes CRT (C RunTime) que l' CreateThreadAPI ne ferait pas.

Une conséquence si vous utilisez l' CreateThreadAPI au lieu d'utiliser des _begingthreadexappels aux fonctions CRT peut provoquer des problèmes inattendus.

Consultez cet ancien Microsoft Journal de Richter.

Ehsan Samani
la source
-2

Il n'y a plus de différence entre les deux.

Tous les commentaires sur les fuites de mémoire, etc. sont basés sur des versions <VS2005 très anciennes. J'ai fait des tests de résistance il y a des années et pourrais démystifier ce mythe. Même Microsoft mélange les styles dans leurs exemples, n'utilisant presque jamais _beginthread.

Lothar
la source
CreateThread : «Si un thread créé à l'aide de CreateThread appelle le CRT, le CRT peut terminer le processus dans des conditions de mémoire insuffisante.»
IInspectable le
Sur la base de la subsentence "nécessite l'utilisation de la version multithread du CRT" je suppose qu'il s'agit de déchets de documentation car il n'y a plus de version crt multithread et depuis de nombreuses années maintenant.
Lothar
«il n'y a plus de version crt multithread» - Le MSDN affirme que «[l] e CRT monothread n'est plus disponible». Vous ne pouvez pas tous les deux avoir raison. J'irai avec le MSDN ici aussi.
IInspectable le
C'était une faute de frappe, bien sûr, je voulais dire que le thread unique est parti et que le multithread est devenu la norme et ce qui a disparu, c'est la distinction entre l'utilisation ou non des threads.
Lothar
Cela devient vraiment étrange. Vous utilisez maintenant une instruction, qui est sans aucun doute correcte ( "nécessite l'utilisation de la version multithread du CRT" ) pour affirmer que cette instruction ainsi que le reste de la documentation sont très probablement erronées? Cela ne semble pas juste.
IInspectable le