Question

Un exemple de code illustrant la création de threads à l'aide de MFC déclare que la fonction de thread est statique et __cdecl . Pourquoi ce dernier est-il requis? Les discussions booster ne s'embarrassent pas de cette convention, est-ce donc un anachronisme?

Par exemple (MFC):

static __cdecl UINT MyFunc(LPVOID pParam)
{
...
}

CWinThread* pThread = AfxBeginThread(MyFunc, ...);

Attendu que Boost:

static void func()
{
...
}

boost::thread t;
t.create(&func);

(les exemples de code pourraient ne pas être corrects à 100% car je ne suis nulle part près d'un IDE).

Quel est l'intérêt de __cdecl? Comment cela aide-t-il lors de la création de threads?

Était-ce utile?

La solution

__ cdecl indique au compilateur d'utiliser la convention d'appel C (par opposition à stdcall, fastcall ou toute autre convention d'appel supportée par votre compilateur). Je crois que VC ++ utilise stdcall par défaut.

La convention d'appel a une incidence sur des éléments tels que la manière dont les arguments sont placés dans la pile (ou les registres dans le cas de fastcall) et le fait de supprimer les arguments de la pile (appelant ou appelé).

Dans le cas de Boost. Je crois qu’il utilise la spécialisation des modèles pour déterminer le type de fonction et la convention d’appel appropriés.

Autres conseils

Regardez le prototype pour AfxBeginThread ( ) :

CWinThread* AfxBeginThread(
   AFX_THREADPROC pfnThreadProc,
   LPVOID pParam,
   int nPriority = THREAD_PRIORITY_NORMAL,
   UINT nStackSize = 0,
   DWORD dwCreateFlags = 0,
   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL 
);

AFX_THREADPROC est une définition de type pour UINT (AFX_CDECL *) (LPVOID) . Lorsque vous transmettez une fonction à AfxBeginThread () , il doit correspondre à ce prototype, y compris la convention d'appel.

Les pages MSDN sur __ cdecl et __ stdcall (ainsi que __ fastcall et __ thiscall ) expliquent le pour et le contre de chaque convention d'appel.

Le Le constructeur> boost :: thread utilise des modèles pour vous permettre de transmettre un pointeur de fonction ou un objet de fonction appelable, de sorte qu'il n'a pas les mêmes restrictions que MFC.

Parce que votre thread va être appelé par une fonction d'exécution qui le gère pour vous, et cette fonction s'attend à ce qu'il en soit ainsi. Boost l'a conçu différemment.

Placez un point d'arrêt au début de votre fonction de thread et examinez la pile lorsqu'elle est appelée. Vous verrez alors la fonction d'exécution qui vous appelle.

Les compilateurs C / C ++ utilisent par défaut la convention d’appel C (en poussant le paramètre le plus à droite en premier sur la pile) car elle permet de travailler avec des fonctions avec un nombre variable d’argument comme printf.

La convention d'appel Pascal (ou "fastcall") pousse d'abord le paramètre le plus à gauche. C’est plus rapide, mais cela vous coûte la possibilité de fonctions à arguments variables simples (je lis quelque part, elles sont toujours possibles, bien que vous ayez besoin de quelques astuces).

En raison de la vitesse résultant de l'utilisation de la convention Pascal, les API Win32 et MacOS utilisent par défaut cette convention d'appel, sauf dans certains cas.

Si cette fonction n'a qu'un paramètre, en théorie, utiliser l'une ou l'autre des conventions d'appel serait légal, bien que le compilateur puisse appliquer la même convention d'appel afin d'éviter tout problème.

Les librairies boost ont été conçues avec le souci de la portabilité. Elles doivent donc être agnostiques quant à la convention d'appelant utilisée par un compilateur particulier.

La vraie réponse a trait à la façon dont Windows appelle en interne la routine de proc du thread et attend de la fonction qu'elle respecte une convention d'appel spécifique, qui est dans ce cas une macro, WINAPI, qui est définie selon mon système. comme:

#define WINAPI      __stdcall

Cela signifie que la fonction appelée est responsable du nettoyage de la pile. La raison pour laquelle boost :: thread est capable de supporter des fonctions arbitraires est qu’elle transmet un pointeur à l’objet function utilisé dans l’appel de thread :: create function à CreateThread. Le threadproc associé au thread appelle simplement operator () sur l'objet function.

La raison pour laquelle MFC requiert __cdecl est donc liée à la façon dont il appelle en interne la fonction transmise à l'appel à AfxBeginThread. Il n’ya aucune bonne raison de le faire à moins qu’ils envisagent d’autoriser les paramètres vararg ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top