Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Un probleme comme on les aime bien :-)

7 réponses
Avatar
Aurélien REGAT-BARREL
Hello,
J'utilise un SDK qui me permet de piloter une caméra scientifique. J'arrive
à m'en servir, mais j'ai un souci : de temps en temps (on trouve pas
pourquoi vu que ça semble aléatoire, connectique en cause ? bug du SDK (très
probable vu la qualité générale du soft) ?) certaines fonctions (vu que ça
plante on sait pas lesquelles...) freezent et du coup mon appli est figée
elle aussi.
Je voudrais donc créer une petite couche intermédiaire qui wrapp cette API
(du C basique) et est capable d'en détecter un plantage (timeout sur les
appels). => je veux un watchdog en fait.
Comment faire ça de manière efficace ?
J'avais pensé à wrapper chaque appel par une fonction qui balance ça dans un
nouveau thread + WaitForSignleObject avec timeout & kill du thread si ça
plante. Mais c'est pas mal de boulot (une trentaine de fonctions à wrapper
:-/) et créer à chaque appel un thread c'est peut être pas top nivo perf
Sinon placer mon code tout entier de pilotage dans un thread, mais c'est pas
évident du tout (interraction avec l'utilisateur...) et ça oblige à se
prendre la tête côté client. J'aimerais une solution transparente (juste
déclenchement d'une exception en cas de freeze).
Quels sont vos idées ?

--
Aurélien REGAT-BARREL

7 réponses

Avatar
Dominique Vaufreydaz
Salut,

J'utilise un SDK qui me permet de piloter une caméra scientifique.
J'arrive à m'en servir, mais j'ai un souci : de temps en temps (on
trouve pas pourquoi vu que ça semble aléatoire, connectique en cause
? bug du SDK (très probable vu la qualité générale du soft) ?)
certaines fonctions (vu que ça plante on sait pas lesquelles...)
freezent et du coup mon appli est figée elle aussi.
Je voudrais donc créer une petite couche intermédiaire qui wrapp
cette API (du C basique) et est capable d'en détecter un plantage
(timeout sur les appels). => je veux un watchdog en fait.
Comment faire ça de manière efficace ?
J'avais pensé à wrapper chaque appel par une fonction qui balance ça
dans un nouveau thread + WaitForSignleObject avec timeout & kill du
thread si ça plante. Mais c'est pas mal de boulot (une trentaine de
fonctions à wrapper :-/) et créer à chaque appel un thread c'est peut
être pas top nivo perf Sinon placer mon code tout entier de pilotage
dans un thread, mais c'est pas évident du tout (interraction avec
l'utilisateur...)



Euh, ca va quand meme pas chercher tripette...

et ça oblige à se prendre la tête côté client.



Moyennement quand meme !

J'aimerais une solution transparente (juste déclenchement d'une
exception en cas de freeze).



A part 1 thread qui fait ca pour toi, que tu peux tuer si ca te prend
trop de temps, je vois pas vraiment... Si t'as pas d'info en provenance
du materiel...

Meme avec des timer (brrrrrrrrrr), tu peux faire ca qu'avec un thread...

Te connaissant, je vois pas la difficulte la !

Doms.
--
Impose ta chance, serre ton bonheur et va vers ton risque.
A te regarder, ils s'habitueront.
René Char, Les Matinaux.
----
http://Dominique.Vaufreydaz.free.fr/
http://TitchKaRa.free.fr/
http://logiciels.ntfaqfr.com/
Avatar
Remi Thomas
Dominique Vaufreydaz wrote:

A part 1 thread qui fait ca pour toi, que tu peux tuer si ca te
prend trop de temps, je vois pas vraiment... Si t'as pas d'info
en provenance du materiel...




Salut,

Je pense comme Doms.
Par exemple tu ajoutes l'incrément d'un compteur dans les boucles des
modules qui plantes. Tout ceci est dans un thread particulier.
Un autre thread regarde si ce compteur évolue sinon il tue l'autre tache.

Rémi

--
Rémi Thomas - MVP Visual C++
Développeur Windows indépendant
http://www.xtware.com/cv
Avatar
Aurélien REGAT-BARREL
Salut Doms, ça faisait longtemps :-)
Que deviens-tu ?

> Sinon placer mon code tout entier de pilotage
> dans un thread, mais c'est pas évident du tout (interraction avec
> l'utilisateur...)

Euh, ca va quand meme pas chercher tripette...



Je t'assure c'est pas évident. Il y a d'abord l'initialisation de la caméra,
puis le mec peut autant de fois qu'il le veut capturer une image, et enfin
le shutdown. Il y a ainsi plusieurs tronçons de code qui appellent le SDK.

// OnInit()
camera.Init(); // timeout court

//... OnClick
MessageBox( "Vous être prêts pour la capture ?" ); // <- timeout
impossible ici car il faut cliquer...
camera.Capture(); // timeout qui dépend du temps de pause de la
caméra...

// OnQuit
camera.shutdown(); // timeout court

> et ça oblige à se prendre la tête côté client.

Moyennement quand meme !



Faut a chaque fois une nouvelle fonction thread à laquelle on va passer
l'objet caméra, et si y'a une progressbar à faire avancer par exemple ça se
corse encore... Car plus ça va aller et plus la camera va être utilisée à
divers endroits et pfff, bonjour le couplage du code.

A part 1 thread qui fait ca pour toi, que tu peux tuer si ca te prend
trop de temps, je vois pas vraiment... Si t'as pas d'info en


provenance
du materiel...



Ben si mais c'est justement par exemple l'appel à la fonction qui donne des
infos sur le matos qui plante quelques rares fois... :-/
Donc je pense bien à utiliser un thread, ce qui me dérange c'est de créer un
thread à chaque appel de fonction... Imagine la création d'un thread à
chaque appel Win32...

Meme avec des timer (brrrrrrrrrr), tu peux faire ca qu'avec un


thread...
Là je vois pas. Comment un timer peut m'aider ?

Exemple simple :

vois freeze()
{
while ( true );
}

Je veux appeler freeze() et être capable de "rompre" l'appel au bout d'un
certains temps. Avec un seul thread je vois pas.

Alors j'ai pondu ça : une classe SafeCaller qui maintient un seul thread qui
est utilisé pour faire tous les appels. Au lieu de faire ce que je pensais
au début :

bool CallFreeze()
{
CreateThread( freeze );
WaitForSingleObject( timeout );
if ( echec du wait )
{
TerminateThread();
return false; // echec de l'appel
}
return true;
}

j'ai un thread qui tourne tout le temps :

void (*fct)(); // pointeur de fonction à appeler depuis le thread
HANDLE hDoCall; // event qui déclenche le call
HANDLE hCallDone; // event qui signale que le call a été fait

ThreadProc()
{
while ( true)
{
WaitForSingleObject( hDoCall ); // attendre demande de call
(fct)(); // appeler
SetEvent( hCallDone ); // appel terminé
}
}

et ma fonction CallFreeze devient :
bool CallFreeze()
{
fct = freeze; // fonction à appeler depusi le thread
SetEvent( hDoCall ); // faire l'appel
WaitForSingleObject( hCallDone, timeout ); // attendre avec timeout
if ( echec du wait )
{
TerminateThread();
CreateThread( ThreadProc ); // relancer le thread
return false; // echec de l'appel
}
return true;
}

En combinant ça avec des fonctions template C++ je pense arriver facilement
à wrapper toutes mes fonctions.

class SafeCaller
{
public:
typedef void(*callback_t)() ;

public:
SafeCaller() :
fct( 0 ), hEvtDoCall( NULL ), hEvtCallDone( NULL ), hThread( NULL )
{
this->hEvtDoCall = ::CreateEvent(
NULL,
FALSE,
FALSE,
NULL );
this->hEvtCallDone = ::CreateEvent(
NULL,
FALSE,
FALSE,
NULL );

this->StartThread();
}

~SafeCaller()
{
// terminer le thread
Call( SafeCaller::Exit, 0 );
::CloseHandle( this->hThread );
::CloseHandle( this->hEvtCallDone );
::CloseHandle( this->hEvtDoCall );
}

bool Call( callback_t Fct, DWORD Timeout )
{
this->fct = Fct;
// lancer l'execution de Fct dans l'autre thread
::SetEvent( this->hEvtDoCall );
// 2 sec de timeout
DWORD ret = ::WaitForSingleObject( this->hEvtCallDone, Timeout );
if ( ret != WAIT_OBJECT_0 )
{
// tuer le thread
::TerminateThread( this->hThread, 0 );
::CloseHandle( this->hThread );
// relancer
this->StartThread();
return false; // echec de l'appel
}
return true; // ok
}

private:
static DWORD WINAPI ThreadProc( LPVOID Params )
{
SafeCaller * sc = reinterpret_cast<SafeCaller*>( Params );
while ( true )
{
// attendre un appel à faire
::WaitForSingleObject( sc->hEvtDoCall, INFINITE );
// effectuer l'appel
(sc->fct)();
// signaler appel terminé
::SetEvent( sc->hEvtCallDone );
}
}

// pour faire terminer le thread
static void Exit()
{
::ExitThread( 0 );
}

void StartThread()
{
LPVOID params = reinterpret_cast<LPVOID>( this );
this->hThread = ::CreateThread(
NULL,
0,
SafeCaller::ThreadProc,
params,
0,
NULL );
}

private:
callback_t fct;
HANDLE hEvtDoCall;
HANDLE hEvtCallDone;
HANDLE hThread;
};

void freeze()
{
while ( true ) ;
}

void ok1()
{
::Sleep( 500 );
}

void ok2()
{
}

int main( int argc, char ** argv )
{
const int timeout = 2000;
SafeCaller caller;
cout << caller.Call( ok1, timeout ) << 'n';
cout << caller.Call( ok2, timeout ) << 'n';
cout << caller.Call( freeze, timeout ) << 'n';

return 0;
}

--
Aurélien REGAT-BARREL
Avatar
Dominique Vaufreydaz
Bonjour,

Je t'assure c'est pas évident. Il y a d'abord l'initialisation de la
caméra, puis le mec peut autant de fois qu'il le veut capturer une
image, et enfin le shutdown. Il y a ainsi plusieurs tronçons de code
qui appellent le SDK.



Je le fait tout le temps dans mon code...

Faut a chaque fois une nouvelle fonction thread à laquelle on va
passer l'objet caméra, et si y'a une progressbar à faire avancer par
exemple ça se corse encore... Car plus ça va aller et plus la camera
va être utilisée à divers endroits et pfff, bonjour le couplage du
code.



Ben tu ecrit une classe qui execute du code avec un timeout
Donc la classe a un thread en permanence. Elle lui donne
des ordre avec des messages (bof, c'est mega lent)
ou une liste chainée mutexées de chose a faire (genre appelle
cette fonction, avec cette structure de parametre, et attend
au max x milliseconde pour finir). Ensuite, si ca reussit, le thread
roule et attends de nouveau un ordre, si ca roule pas, elle le tue
et relance un thread?

Ben si mais c'est justement par exemple l'appel à la fonction qui
donne des infos sur le matos qui plante quelques rares fois... :-/
Donc je pense bien à utiliser un thread, ce qui me dérange c'est de
créer un thread à chaque appel de fonction... Imagine la création
d'un thread à chaque appel Win32...



Ben non, juste quand ca merde !

Meme avec des timer (brrrrrrrrrr), tu peux faire ca qu'avec un


thread...
Là je vois pas. Comment un timer peut m'aider ?

Exemple simple :

vois freeze()
{
while ( true );
}

Je veux appeler freeze() et être capable de "rompre" l'appel au bout
d'un certains temps. Avec un seul thread je vois pas.



Ben ton thread principal (celui qui donne l'ordre a l'autre de bosser)
et un thread qui execute ton appel.

Alors j'ai pondu ça : une classe SafeCaller qui maintient un seul
thread qui est utilisé pour faire tous les appels. Au lieu de faire
ce que je pensais au début :



Ah ben voila.

bool CallFreeze()
{
CreateThread( freeze );
WaitForSingleObject( timeout );
if ( echec du wait )
{
TerminateThread();
return false; // echec de l'appel
}
return true;
}

j'ai un thread qui tourne tout le temps :

void (*fct)(); // pointeur de fonction à appeler depuis le thread
HANDLE hDoCall; // event qui déclenche le call
HANDLE hCallDone; // event qui signale que le call a été fait

ThreadProc()
{
while ( true)
{
WaitForSingleObject( hDoCall ); // attendre demande de call
(fct)(); // appeler
SetEvent( hCallDone ); // appel terminé
}
}

et ma fonction CallFreeze devient :
bool CallFreeze()
{
fct = freeze; // fonction à appeler depusi le thread
SetEvent( hDoCall ); // faire l'appel
WaitForSingleObject( hCallDone, timeout ); // attendre avec timeout
if ( echec du wait )
{
TerminateThread();
CreateThread( ThreadProc ); // relancer le thread
return false; // echec de l'appel
}
return true;
}

En combinant ça avec des fonctions template C++ je pense arriver
facilement à wrapper toutes mes fonctions.



Y'aurait plus simple mais tu vois que ca marche et que tu peux le faire
en
plus ;-D. Perso, je vois pas d'autres alternatives.

Doms.
--
Impose ta chance, serre ton bonheur et va vers ton risque.
A te regarder, ils s'habitueront.
René Char, Les Matinaux.
----
http://Dominique.Vaufreydaz.free.fr/
http://TitchKaRa.free.fr/
http://logiciels.ntfaqfr.com/
Avatar
Aurélien REGAT-BARREL
> Y'aurait plus simple mais tu vois que ca marche et que tu peux le


faire
en
plus ;-D. Perso, je vois pas d'autres alternatives.



C'est l'histoire du timer qui m'a perturbé.
Pour le + simple, tu peux développer un peu ?
Thx.

--
Aurélien REGAT-BARREL
Avatar
Aurélien REGAT-BARREL
> Salut,


Hello,

Je pense comme Doms.
Par exemple tu ajoutes l'incrément d'un compteur dans les boucles des
modules qui plantes. Tout ceci est dans un thread particulier.
Un autre thread regarde si ce compteur évolue sinon il tue l'autre tache.



Je vais faire en sychrone :
- le thread "maître" lance l'execution de la fonction dans un thread "bac à
sable"
- il lui donne un certains temps pour effectuer l'appel (normelement, c'est
quasi instantané)
- si le timeout a expiré fiout tuage de thread, message d'erreur, modissage
des programmeurs de ce SDK (et encore c'est mieux là, ça ne fait *que*
planter mon appli : la version d'avant provoquait des écrans bleus sous
Win2K).

Reste à implémenter tout ça de manière élégante, avec peu d'impect sur le
code existant. Je part sur un objet Caller qui controle le thread et Callee
qui wrapp chacune des fonctions à appeler, Caller executant des Callee...
Pas d'échange de message, juste une struct Callee qui est passée à Caller et
qui pointe sur la fonction à appeler, les paramètres, etc...
J'ai pas trouvé plus simple que 2 events pour que
- le thread maitre lance une execution sur le thread 2 : SetEvent(
hEvtDoExecution )
- que ce dernier informe thread1 que l'execution s'est bien passée (timeout
sur l'event "j'ai fini d'executer").

Thread2 :
while ( true )
{
WaitForSingleObject( hEvtDoExecution )
// effectuer l'appel
SetEvent( hEvtExecutionDone );
}

Thread1:
// initialiser les parametres d'execution
SetEvent( hEvtDoExecution ) // lancer
WaitForSingleObject( hEvtExecutionDone, timeout ) // attendre

Vous voyez plus simple ?
Merci.

--
Aurélien REGAT-BARREL
Avatar
Dominique Vaufreydaz
Salut,

C'est l'histoire du timer qui m'a perturbé.
Pour le + simple, tu peux développer un peu ?



Ben le plus simple c'est ce que t'as fait (cf ton post en reponse a
Remi).
Au lieu de faire un wrapper complet, moi j'ai fait un executeur qui sait
executer les procedures en leur passant des pamametres. Donc je lui
file en argument une classe (structure, y'a pas de methode) avec ce
qu'il doit faire
et lui le fait. Et ensuite, comme tu le disais, tu mets un event et hop
ca doit rouler.

Voila. Doms.
--
Impose ta chance, serre ton bonheur et va vers ton risque.
A te regarder, ils s'habitueront.
René Char, Les Matinaux.
----
http://Dominique.Vaufreydaz.free.fr/
http://TitchKaRa.free.fr/
http://logiciels.ntfaqfr.com/