Problème avec _beginthread... [Allons plus loin] [Visual C++] - C++ - Programmation
Marsh Posté le 27-05-2002 à 18:18:41
je suis pas sur que ça soit la solution mais en tout cas, les fonctions de thread doivent être déclarées en static .
Marsh Posté le 27-05-2002 à 18:52:44
C'est possible, en tout cas quand je déclare la fonction appelée normalement, pas dans une classe, il n'y a aucun problème. Alors comment faire pour qu'elle soit acceptée lorsqu'elle fait partie d'une classe ?
Sinon j'ai un autre problème concernant les arguments à passer à la fonction appelée. Je souhaite en passer 2, comment faire ? 1 pas de problème, mais 2... est-on obligé de passer par une structure contenant les arguments ?
Marsh Posté le 27-05-2002 à 19:54:00
Oui à l'instant, ça marche, merci beaucoup
Reste le problème des arguments, si tu m'aider...
thx
Marsh Posté le 27-05-2002 à 20:10:27
essaie ceci :
Citation : |
A+ mon ex-boolay
[jfdsdjhfuetppo]--Message édité par Harkonnen le 27-05-2002 à 20:11:22--[/jfdsdjhfuetppo]
Marsh Posté le 27-05-2002 à 20:12:14
Merci Harkonnen mais le fait de mettre static devant la fonction dans la classe résout le problème
Mais je suis toujours embeté avec ces 2 arguments de type différent :
Voici mon code de passage de 2 arguments (de type différent !) :
void *arg[2];
arg[0] = pDialog;
arg[1] = (void*)n;
_beginthread(FonctionAppelee,0,arg);
pour l'instant, pas de problème, c'est pour les récupérer que je bloque :
en effet la fonction lancée en thread doit impérativement prendre (void* arg) comme param.
Donc comment reprendre les 2 arguments passés via ce void* arg ?
Marsh Posté le 27-05-2002 à 20:53:50
Le problème de départ (__cdecl) n'est pas totalement résolu :
mettre static résoud le problème mais je ne peux plus dans la fonction static modifier ma classe :
illegal reference to data member 'CMaClasse::membre' in a static member function
Donc j'ai pris la solution à Harkonnen qui fonctionne très bien :
mettre __cdecl lors de la déclaration dans la classe ainsi que lors de la définition de la fonction (cf ci-dessus).
Mais je ne peux pas imbriquer 2 fonctions __cdecl, y a toujours la même erreur (début du topic), je m'explique :
class CMaClasse
{
public:
void __cdecl FonctionAppelant(void* args);
private:
void __cdecl FonctionAppelee(void* arg);
};
void __cdecl CMaClasse::FonctionAppelant(void* args)
{
_beginthread(FonctionAppelee,0,(void*)a); //la y a toujours un problème !
}
void __cdecl CMaClasse::FonctionAppelee(void* arg)
{
//...
}
void CUneAutreClasse::OnButton1(void)
{
CMaClasse test;
_beginthread(FonctionAppelant,0,this); //la aucun problème
}
donc le premier _beginthread (une autre classe appelle), il n'y a aucun pb. Mais la fonction qui vient d'être appelée doit appeler à son tour une autre fonction et la l'erreur resurgit même avec __cdecl.
Donc une fonction, pas de problème (soit static, soit __cdecl), mais après... Pas facile ces 2 threads imbriqués !
P.S : et puis y a toujours le problème des arguments, enfin chaque chose en son temps !
Marsh Posté le 27-05-2002 à 21:04:40
pour les arguments, faut que tu castes tes arguments (enfin, moi, c'est comme ça que je ferais) :
tu as
void *arg[2];
arg[0] = pDialog;
arg[1] = (void*)n;
_beginthread(FonctionAppelee,0,arg);
dans ton thread, tu fais ensuite
CDialog *pDialog = (CDialog*)arg[0];
void *n = (void*)arg[1];
et voilà comment tu récupères tes arguments ! enfin, je pense...
Marsh Posté le 27-05-2002 à 21:10:16
Citation : Donc une fonction, pas de problème (soit static, soit __cdecl), mais après |
Il y a plusieurs conventions d'appels.
Les membres d'un classe sont par défaut thiscall, et sinon c'est __cdecl.
Une fonction static n'est pas une véritable fonction membre, elle est donc __cdecl.
Pour les paramètres, le mieux est de créer ton propre type (une structure que tu définis dans ta classe) et de passer un pointeur sur une variable de ce type.
Marsh Posté le 27-05-2002 à 21:34:33
Pour les paramètres voila l'erreur (même avec un cast)
cannot convert parameter 3 from 'CMaClasse::ARGS' to 'void *'
mais je ne sais toujours pas comment faire avec mes 2 _beginthread
ca me prends la tête...............
Marsh Posté le 27-05-2002 à 22:13:13
antsite a écrit a écrit : Salut, Je me heurte actuellement à un problème avec la fonction _beginthread : class CMaClasse { public: void FonctionAppelant(void* args); private: void FonctionAppelee(void* arg); }; void CMaClasse::FonctionAppelant(void* args) { _beginthread(FonctionAppelee,0,(void*)a); //la y a un problème } void CMaClasse::FonctionAppelee(void* arg) { //... } Le compilo de Visual C++ me sort ça comme erreur : [...] error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)' Peut-on m'aider ? Merci ANT |
Salut, ton probleme c que tu utilise des classes et tu n'as pas le droit de faire ca... je le sais j'ai eu le meme probleme.
La seule solution est d'utilisé les classes thread de la MFC (classe CWinThread) ou alors tu galère a faire des fonctions en c static et tu t'amuse avec les pointeurs sur fonctions mais la c tres crade...
En esperant avoir repondu a ta question...
@+
Marsh Posté le 28-05-2002 à 13:39:05
Ok donc je ne vais pas déclarer ces fonctions dans des classes.
merci
Marsh Posté le 28-05-2002 à 17:18:12
Cela se révèle donc difficile d'utiliser des fonctions membres d'une classe avec _beginthread. Donc je vais devoir les déclarer en tant que 'simples' fonctions :
void FonctionAppelant(void* pDialog);
void FonctionAppelee(void* pDialog);
class CMaClasse
{
public:
static int var;
bool var2;
};
Seulement que faire du reste de la classe, car cette classe ne présente désormais plus grand intérêt si ces 2 fonctions n'en font pas partie. J'ai dans la classe 2 autres membres, dont un en static.
Dois-je déclarer en variables globales les 2 membres ou les laisser dans la classe où ils seront les 2 seuls membres ? Je vous serais reconnaissant si vous pouviez me proposer un schéma propre d'architecture de mon application, merci.
Une autre question mois importante, pour les arguments, comment faire pour déclarer et définir la struct à utiliser : déclaration & définition dans la classe, ou seulement déclaration, ou l'inverse ?
Marsh Posté le 28-05-2002 à 18:51:19
Ba la c sur ta classe elle va plus servir a grand chose...
le truc c que tu fait une classe thread declarer en gros comme ca :
class C_MyThread : public CWinThread
{
public:
C_MyThread(void);
virtual ~C_MyThread(void);
// et tu rajoute tes fonctions si besoin
}
et tu fabrique une autre classe qui elle appellera ta classe thread de la facon suivante :
...
thread1 = (C_MyThread *) AfxBeginThread(RUNTIME_CLASS(C_MyThread), THREAD_PRIORITY_NORMAL, 0, 0x4);
thread1->ResumeThread();
...
si tu veux plus de precision sur les parametres de AfxBeginThread regarde dans les MSDN.
Marsh Posté le 28-05-2002 à 23:30:47
Si tu veux réinventer la roue:
Il ya des bouts de code un peu vilain ( pour la la terminaison du thread) mais ça fonctionne.
DECLARATION
class CThread
{
public:
void PostMessage(UINT message);
BOOL GetMessage(UINT message);
void Resume(void);
void Suspend(void);
virtual void Terminate(void);
CDAQThread();
virtual ~CDAQThread();
protected:
virtual void Quit(void);
virtual void Run(void);
virtual void Init(void);
virtual BOOL GetMessage(MSG*);
virtual void PostMessage(MSG* pMsg);
private:
HANDLE m_hThread;
DWORD m_dwThreadId;
private:
static void Thread(LPVOID lpvParameter);
};
IMPLEMENTATION:
CThread ::CThread ()
{
m_hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CDAQThread::Thread, (LPVOID)this, CREATE_SUSPENDED , &m_dwThreadId );
}
CThread ::~CThread ()
{
}
void CThread ::Init()
{
}
void CThread ::Run()
{
}
void CThread ::Quit()
{
}
void CThread ::Suspend()
{
if(m_hThread)
::SuspendThread(m_hThread);
}
void CThread ::Resume()
{
if(m_hThread)
::ResumeThread(m_hThread);
}
void CThread ::Thread(LPVOID lpvParameter)
{
CDAQThread* pDAQThread=(CDAQThread*)lpvParameter;
pDAQThread->Init();
pDAQThread->Run();
pDAQThread->Quit();
}
void CThread ::PostMessage(MSG* pMsg)
{
if(pMsg)
::PostThreadMessage(m_dwThreadId,pMsg->message,pMsg->wParam,pMsg->lParam);
}
BOOL CThread ::GetMessage(MSG* pMsg)
{
return ::GetMessage(pMsg,NULL,0,0);
}
BOOL CThread ::GetMessage(UINT message)
{
MSG msg;
return ::GetMessage(&msg,NULL,message,message);
}
void CThread ::Terminate()
{
if(m_hThread)
::TerminateThread(m_hThread,0);
DWORD dwExitCode;
DWORD dwTimeout=DAQTHREAD_TIMEOUT;
while(GetExitCodeThread(m_hThread,&dwExitCode) && dwExitCode==STILL_ACTIVE){
Sleep(100);
if(!(dwTimeout--)) return;
}
::CloseHandle(m_hThread);
}
void CThread ::PostMessage(UINT message)
{
::PostThreadMessage(m_dwThreadId,message,0,0);
}
Marsh Posté le 30-05-2002 à 17:33:48
phlb a écrit a écrit : void CThread ::Terminate() { if(m_hThread) ::TerminateThread(m_hThread,0); (...) |
attention avec TerminateThread... c'est une fonction très peu sécurisée !
voir MSDN pour tous les saccages provoqués par cette fonction !
Marsh Posté le 27-05-2002 à 17:39:12
Salut,
Je me heurte actuellement à un problème avec la fonction _beginthread :
class CMaClasse
{
public:
void FonctionAppelant(void* args);
private:
void FonctionAppelee(void* arg);
};
void CMaClasse::FonctionAppelant(void* args)
{
_beginthread(FonctionAppelee,0,(void*)a); //la y a un problème
}
void CMaClasse::FonctionAppelee(void* arg)
{
//...
}
Le compilo de Visual C++ me sort ça comme erreur :
[...] error C2664: '_beginthread' : cannot convert parameter 1 from 'void (void *)' to 'void (__cdecl *)(void *)'
Peut-on m'aider ?
Merci
ANT
[jfdsdjhfuetppo]--Message édité par antsite le 28-05-2002 à 17:17:51--[/jfdsdjhfuetppo]