Multi tâches

El Rabou Messages postés 4 Date d'inscription jeudi 16 décembre 2004 Statut Membre Dernière intervention 17 mai 2005 - 17 mai 2005 à 11:43
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 - 17 mai 2005 à 17:18
Bonjour
je cherche a faire un thread qui soit une méthode d'un objet celle-ci étant non statique.
Le tout en Visual C++ 6. Bien sûr j'ai trouvé l'astuce de passer la fenêtre en paramètre au thread, mais cela ne me satisfait pas pour des raisons de design UML.
J'utilise actuellement CreateThread( ) pour créer le thread ce n'est peut etre de la que vient le problème (CreateThread n'accepte que les méthodes statiques ? ) .
Je suis preneur de toute suggestion.
Merci

C'est le manque de foi qui rend fous les hommes...

26 réponses

cs_Arnotic Messages postés 933 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 9 janvier 2012
17 mai 2005 à 11:51
Comment veux-tu créer un thread sur une fonction qui n'a pas d'adresse mémoire fixe (donc non statique) ?
C'est physiquement impossible. Donc il faut que ce soit une fonction statique tout comme pour les callbacks.

@+
Arnotic,
Admin CS, MVP Visual C++
0
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
17 mai 2005 à 12:01
En ce qui me concerne j'ai du mal à comprendre pourquoi ca ne marche
pas, une méthode étant juste une fonction normal prenant en plus en
paramètre (implicite) un objet. Cela a-t-il un rapport avec l'héritage
et les méthodes virtuelles?
0
ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 7
17 mai 2005 à 12:19
Justement ce paramètres implicite empêche les callback d'être appelées car il faut fournir le pointeur this que l'API Win32 est incapable de deviner lors de l'appel à la fonction CALLBACK. Le seul moyen serait de lui fournir en paramètre ce pointeur ce qui est tout de même possible car en général on peut fournir un param en plus de la CALLBACK que le prog peut reconvertir en pointeur sur l'objet. La CALLBACK peut ensuite appeler une fonction membre. Il faut obligatoirement passer par cette étape...
0
cs_Arnotic Messages postés 933 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 9 janvier 2012
17 mai 2005 à 12:31
Pour créer une callback ou un thread il te faut une adresse mémoire fixe pour une fonction à la compilation. Hors en C++ avec les class tu n'as plus ca. Donc tu es obligé de définir statique si tu veux en avoir un.

@+
Arnotic,
Admin CS, MVP Visual C++
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
17 mai 2005 à 13:33
Oui ymca je comprends, pourtant l'adresse d'une fonction membre est bien fixe, je vois pas comment elle pourrait varier.

En fait le problème de compilation survient quand le compilo se rend
compte que la fonction est une fonction membre non-static, je me trompe?
0
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
17 mai 2005 à 14:17
salut,

Arnotic: une methode non statique d'une classe a une adresse fixe (sauf
si la fonction est virtuelle). Le truc c'est qu'une methode non
statique recoit en plus implicitement la valeur du pointeur this (qui
est passé a travers ecx ou edx d'ailleurs).

El Rabou: Cree une fonction static de la forme la:

class test

{

static int functhread(test* param)

{

if (!param)

return 0;

test& theObject = *param;

// mtnt theObject designe l'objet que tu avais créé

// etc...



return 1;

}

si ton design uml foire, c'est que il y a quelque chose de mal
concu.... de toute facons faire ceci est perilleux car entre temps;
theObject peut ne plus exister dans le thread principal ou il a été
créé... donc dans ton diagramme il faut bien s'assurer que sa durée de
vie est plus grande que celle du thread (peut etre est-ce un singleton,
et qu'il dure pdt tout le prog ?)



a+
0
El Rabou Messages postés 4 Date d'inscription jeudi 16 décembre 2004 Statut Membre Dernière intervention 17 mai 2005
17 mai 2005 à 14:20
En faite, il y a plusieurs manieres de compiler la techno objet. Le truc, c que je c pas comment visual c++ si prend. Liste chainer de pointeur de fonctions ? decalage ? si quelqu'un pouvait me dire où je peut trouvé ça ... ça m'aiderait à comprendre se qu'il fait, et donc comment il compile, et donc, bien des erreurs. Je ne l'ai pas vue dans la msdn. C'est pourtant le genre de truc façile à trouvé sur d'autre compilo c++ (je vien du monde de l'info indus... et sur microcontroleurs ces informations sont capital et donc spécifié dans les doc)

Merci de votre aide.

C'est le manque de foi qui rend fous les hommes...
0
ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 7
17 mai 2005 à 14:34
Les méhodes non statiques des classes ont bien une adresse fixée à l'édition de lien (il suffit de générer le .map pour le voir).
Le compilo passe simplement un pointeur sur l'objet appelant en param supplémentaire de la méthodes (dans le registre ecx pour x86).

Pour les méthodes non virtuelles on appelle donc simplement la méthode comme n'importe quelle autre fonction.

Pour les méthodes virtuelles c'est différent. Chaque classe ayant au moins une méthode virtuelle possède une table contenant l'addresse des fonctions virtuelles. Cette table est initialisée à la construction de l'objet en fonction de sa véritable classe.
Ainsi 2 objets de 2 classes différentes mais dérivant d'une même classe auront des implémentations différentes pour une méthode virtuelle mais cette méthode sera accessible par le même indice dans la table. Tout ça c'est le compilo qui s'en charge.

Les implémentations des méthodes virtuelles ont bien sûr une addresse fixe connue à l'édition de lien. Cette addresse est mise dans la vtable lors de la construction de l'objet. C'est juste au momemt de l'appel que le compilo passe par la table virtuelle pour récupéper l'adresse de la fonction correspondante à la classe du Runtime. plutot que d'appeler directement la fonction.
0
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
17 mai 2005 à 14:48
j'ai pas bien pigé ta question mais j'essaie d'y repondre :)

si tu passes une fonction non statique comme parametre d'un thread, pourquoi cela ne compile t'il pas?

tout simplement parce que la convention d'appel de ta methode non
statique de ta classe n'est pas la meme que celle d'une fonction
'classique'. Les parametres de la fonction/methode sont bien mis sur la
pile, mais dans le cas d'un appel d'une fonction membre non statique,
le compilateur (vc 6 du moins) stocke dans edx la valeur du
pointeur this, puis appelle la methode "normalement".

en gros si tu ecris ceci:



class test

{

private:

std::string message;

public:

void SetMessage(const char* nvomessage)

{

message = nvomessage;

}

}



test ObjetTest;

ObjetTest.SetMessage( "salut !");



que se passe t'il a ce moment?

pour appeler SetMessage, le compilo place l'adresse de ObjetTest dans
edx, puis il empile l'adresse de la chaine "salut !" sur la pile, et la
il appelle la fonction SetMessage.

A l'interieur de cette fonction, le compilo peut connaitre l'adresse du
std::string message de l'objet ObjetTest, car celui ci se retrouve
facilement a partir de l'adresse de this qui est contenue dans edx (il
est par exemple a l'adresse edx, ou edx+4, ou ... tout depend de
l'existence ou non d'autres champs dans la classe)

Mais maintenant si j'ai une fonction quelconque:

void DireBonjour(const char* msg)

{

std::cout << "bonjour : " << msg << endl;

}



Pour appeler cette fonction, pas besoin de remplir edx... c'est pas une fonction membre d'une classe.



Si tu appelles CreateThread, le compilo t'empeche de passer une
fonction non statique, car CreateThread ne va pa toucher a edx qui doit
pourtant imperativement contenir le pointeur this avant l'appel d'une
fonction membre non statique. Il n'y touche pas, car d'habitude il n'y
a pas besoin d'y toucher ...



tu peux feinter en faisant ca:



class test

{

static int functhread(test* param)

{

if (!param)

return 0;

test& theObject = *param;

// mtnt theObject designe l'objet que tu avais créé

theObject.AppelFuncThreadNonStatique();

// etc...



return 1;

}

void AppelFuncThreadNonStatique(void)

{

// ce que tu veux ... c 'est pas ici une fonction statique

}

}



void main

{

test ObjetTest;

DWORD ThreadId = 0;

CreateThread(NULL, NULL, test::functhread, &ObjetTest, NULL, &ThreadId);

Sleep(INFINITE);

}

et voila si j'ai pu t'eclairer ....
0
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
17 mai 2005 à 14:50
bon ben ymca m'infirme en me disant que c'est dans ecx qu'est passé le
pointeur this ... pour avoir déja regardé, je savais que c'etait l'un
des deux, mais plus lequel exactement .... donc dans ce que j'ai dit
remplacer edx par ecx (c'est assez peu important)

a+
0
cs_Arnotic Messages postés 933 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 9 janvier 2012
17 mai 2005 à 14:52
Pour notre problème il faut que notre code de la fonction soit chargée en mémoire pendant toute l'éxecution du programme à la même adresse sans aucun changement.

Dans ce que tu viens d'énoncer avant, tu te perds dans tes explications. Relis tes premières phrases.

@+
Arnotic,
Admin CS, MVP Visual C++
0
ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 7
17 mai 2005 à 14:58
Arnotic -> qui se perd dans ses explications (moi ou Cosmobob) ?

Parce que que cela soit du C ou du C++ le code ne change pas d'addresse en cours de route, une fois qu'une fonction est chargée à un endroit en mémoire elle n'y bouge plus et donc on peut passer son addresse à une autre fonction. Les fonctions de CALLBACK marche également avec le C++ à condition que la classe soit spécifiée dans la signature de la fonction et que la fonction qui va appelée notre CALLBACK fournisse l'objet (c'est comme cela que marche les MFC et le routage des messages).

Donc je maintiens que le problème avec les CALLBACK des API Win32 c'est pas l'adresse mais le pointeur this.
0
cs_Arnotic Messages postés 933 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 9 janvier 2012
17 mai 2005 à 14:59
c'est peu important edx ou ecx ?????
faut vraiment arrêter les gamineries à un moment. lisez un bon bouquin sur les processeurs et l'assembleur x86 avant de vous lancer dans des débats de ce type.

une adresse mémoire est codée sur 4 octets et elle pointe directement sur du code placée en mémoire. or si on ne déclare pas en statique nous n'ravons pas cette adresse mémoire de connues directement.

@+
Arnotic,
Admin CS, MVP Visual C++
0
ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 7
17 mai 2005 à 15:05
Voici un extrait du .map d'un programme avec des classes

0001:000075e0 [mailto:?WriteString@TProfile@@QAEXPBD@Z ?WriteString@TProfile@@QAEXPBD@Z] 004085e0 f Profile.obj
0001:000076d0 [mailto:?ReadString@TProfile@@QAEXPADI@Z ?ReadString@TProfile@@QAEXPADI@Z] 004086d0 f Profile.obj
0001:00007850 [mailto:_WinMain@16 _WinMain@16] 00408850 f WinMain.obj
0001:00007c30 [mailto:?Reset@TCommBuffer@@QAEXXZ ?Reset@TCommBuffer@@QAEXXZ] 00408c30 f CommBuffer.obj
0001:00007e30 [mailto:?AddData@TCommBuffer@@QAEXPBEHW4TECommByteType@@@Z ?AddData@TCommBuffer@@QAEXPBEHW4TECommByteType@@@Z] 00408e30 f CommBuffer.obj

Tout comme WinMain les méthodes des classes non statiques (TProfile::WriteString, TCommBuffer::Reset) ont une adresse connue au linkage.
0
cs_Arnotic Messages postés 933 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 9 janvier 2012
17 mai 2005 à 15:05
C et C++ rien à voir
C = language non objet
C++ = language orienté programmation objet

pointeur this, et compagnie purement virtuel.
en assembleur pour la callback on veut simplement savoir l'adresse directe de la fonction.
hors si on déclare pas en statique on ne peut pas l'avoir.

@+
Arnotic,
Admin CS, MVP Visual C++
0
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
17 mai 2005 à 15:08
Arnotic, j'ai pas voulu lancer un débat, j'ai juste demandé à
comprendre un truc que j'ai jamais compris, et pour l'instant ce n'est
pas toi qui donne le plus d'explications.

Pourquoi dis-tu qu'on ne connait pas l'adresse d'une méthode non-static?
0
cs_Arnotic Messages postés 933 Date d'inscription dimanche 1 avril 2001 Statut Membre Dernière intervention 9 janvier 2012
17 mai 2005 à 15:11
juste pour info en MFC suffit de regarde un peut le code et on voit des trucs comme :

BEGIN_MESSAGE_MAP

ou


DECLARE_MESSAGE_MAP

et on comprend mieux

@+
Arnotic,
Admin CS, MVP Visual C++
0
ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 7
17 mai 2005 à 15:18
#define DECLARE_MESSAGE_MAP() \
private: \
static const AFX_MSGMAP_ENTRY _messageEntries[]; \
protected: \
static AFX_DATA const AFX_MSGMAP messageMap; \
virtual const AFX_MSGMAP* GetMessageMap() const; \

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return &theClass::messageMap; } \
AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \
{ &baseClass::messageMap, &theClass::_messageEntries[0] }; \
AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
{ \


#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \

#define ON_WM_DESTROY() \
{ WM_DESTROY, 0, 0, 0, AfxSig_vv, \
(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(void))&OnDestroy },

en gros on déclare une table et une fonction.

BEGIN_MESSAGE_MAP()
ON_WM_DESTROY()
END_MESSAGE_MAP()

=> définie une table d'association entre un message (WM_MESSAGE) et une fonction de CWnd (OnDestroy) dont on fournie l'adresse non ?
0
vecchio56 Messages postés 6535 Date d'inscription lundi 16 décembre 2002 Statut Membre Dernière intervention 22 août 2010 14
17 mai 2005 à 15:41
ymca, si comme tu le dis le problème est le pointeur pointeur this, pourquoi ceci ne marche pas:



//////////////////////////////////////////////////////////////////////////////

#include

#include <windows.h>



using namespace std;



class A;

typedef DWORD (*FONCTION)(A* const a, LPVOID LPARAM);

int fonction(FONCTION f){ return 0;}



class A

{

public:

void test()

{

fonction(fct);

cout << "test" << endl;

}



DWORD fct(LPVOID param) {return 0;}

};



int main()

{

A* a = new A();

a->test();

}

//////////////////////////////////////////////////////////////////////////////

L'appel fonction(fct) ne compile pas, et le cast est impossible. Or logiquement c'est fct est bien de type FONCTION
0
ymca2003 Messages postés 2070 Date d'inscription mardi 22 avril 2003 Statut Membre Dernière intervention 3 juillet 2006 7
17 mai 2005 à 16:01
Sauf que le param implicite ne doit pas être mis dan les param mais dans le type :
typedef DWORD (A::*FONCTION)( LPVOID LPARAM);

#include
#include <windows.h>


using namespace std;


class A;
typedef DWORD (A::*FONCTION)(LPVOID LPARAM);
int fonction(FONCTION f);


class A
{
public:
void test()
{
fonction(fct);
cout << "test" << endl;
}

DWORD fct(LPVOID param) {return 0;}
};


int main()
{
A* a = new A();
a->test();
return 0;
}


int fonction(FONCTION f)
{
A othera;
return (othera.*f)(NULL);
}
0
Rejoignez-nous