OVH Cloud OVH Cloud

CreateThread

12 réponses
Avatar
Jean-François GAZET
Bonjour,

Dans une applie Win32, je dois appeler une fonction search() qui peut
prendre une 30taine de secondes et qui contient une boucle infinie stoppée
par une variable globale. Si j'appelle cette fonction search() tel quel,
toute l'appli est gelée et ne répond plus. J'utilise alors :

DWORD thread1;
hThread1=CreateThread(
NULL, // pointer to thread security attributes
0, // initial thread stack size, in bytes
(unsigned long (__stdcall *)(void *))search,
NULL, // argument for new thread
0, // creation flags
&thread1 // pointer to returned thread identifier
);

Mais dans ce cas, il semble que la variable globale censée stopper la
recherche n'ait plus d'effet. Je suppose que le thread est un processus
parallèle et qui démarre avec une copie de cette variable globale. Comment
stopper la recherche avec cette variable globale ?
L'autre problème, qui doit être identique est que si je clique sur la croix
pour fermer la fenêtre pendant une recherche, l'appli quitte seulement quand
le thread est terminé.

Merci de votre aide.

10 réponses

1 2
Avatar
Arnaud Debaene
Jean-François GAZET wrote:
Bonjour,


Bonjour.

Dans une applie Win32, je dois appeler une fonction search() qui peut
prendre une 30taine de secondes et qui contient une boucle infinie
stoppée par une variable globale. Si j'appelle cette fonction
search() tel quel, toute l'appli est gelée et ne répond plus.
J'utilise alors :

DWORD thread1;
hThread1=CreateThread(
NULL, // pointer to thread security attributes
0, // initial thread stack size, in bytes
(unsigned long (__stdcall *)(void *))search,
NULL, // argument for new thread
0, // creation flags
&thread1 // pointer to returned thread identifier
);


n'oublie pas de fermer hThread1 si tu n'en as pas besoin (CloseHandle).

Le fait que tu fasses un cast de sauvage sur search est de mauvaise augure :
la fonction search *doit* avoir pour signature :
long __stdcall search(void* param);
C'est bien le cas? Sinon il est fort probable que ton thread ne démarre pas
ou fasse n'importe quoi.

Mais dans ce cas, il semble que la variable globale censée stopper la
recherche n'ait plus d'effet


1) Variable globale --> mauvaise idée. Pourquoi ne pas passer un pointeur
vers les paramètres dont le thread a besoin dans l'argument de search?
2) Ca devrait marcher aux problèmes de synchro rès. Postes un code complet
minimal de ce que tu fais.

Je suppose que le thread est un
processus parallèle et qui démarre avec une copie de cette variable
globale.


Non, tous les threads d'un processus ârtagent le même espace d'adressage,
donc les mêmes variables.

Comment stopper la recherche avec cette variable globale ?


En la positionnant de manière thread-safe (atomique).

L'autre problème, qui doit être identique est que si je clique sur la
croix pour fermer la fenêtre pendant une recherche, l'appli quitte
seulement quand le thread est terminé.


Normal : il faut notifier ton thread ouvrier de se terminer, en positionnant
cette variable.

Arnaud
MVP - VC
Avatar
Jean-François GAZET
> > Dans une applie Win32, je dois appeler une fonction search() qui peut
> prendre une 30taine de secondes et qui contient une boucle infinie
> stoppée par une variable globale. Si j'appelle cette fonction
> search() tel quel, toute l'appli est gelée et ne répond plus.
> J'utilise alors :
>
> DWORD thread1;
> hThread1=CreateThread(
> NULL, // pointer to thread security attributes
> 0, // initial thread stack size, in bytes
> (unsigned long (__stdcall *)(void *))search,
> NULL, // argument for new thread
> 0, // creation flags
> &thread1 // pointer to returned thread identifier
> );



n'oublie pas de fermer hThread1 si tu n'en as pas besoin (CloseHandle).



Oui, je fais CloseHandle(hThread1); à la fin de la recherche.

Le fait que tu fasses un cast de sauvage sur search est de mauvaise augure


:
la fonction search *doit* avoir pour signature :
long __stdcall search(void* param);
C'est bien le cas? Sinon il est fort probable que ton thread ne démarre


pas
ou fasse n'importe quoi.



La fonction search est définie comme cela : void search(char *s);
Mais si je fais :
hThread1=CreateThread(NULL,0,search,NULL,0,&thread1);
J'ai l'erreur suivante à la compilation :
error C2664: 'CreateThread' : cannot convert parameter 3 from 'void (char
*)' to 'unsigned long (__stdcall *)(void *)'
None of the functions with this name in scope match the target type
Alors en collant 'unsigned long (__stdcall *)(void *), ça marche.

> Mais dans ce cas, il semble que la variable globale censée stopper la
> recherche n'ait plus d'effet
1) Variable globale --> mauvaise idée. Pourquoi ne pas passer un pointeur
vers les paramètres dont le thread a besoin dans l'argument de search?



je ne suis pas expert avec les pointeurs. Je ne comprend pas bien votre
question.

> Comment stopper la recherche avec cette variable globale ?
En la positionnant de manière thread-safe (atomique).



Quel est le code pour cela ?

> L'autre problème, qui doit être identique est que si je clique sur la
> croix pour fermer la fenêtre pendant une recherche, l'appli quitte
> seulement quand le thread est terminé.
Normal : il faut notifier ton thread ouvrier de se terminer, en


positionnant
cette variable.



Arnaud
MVP - VC



Merci.
Avatar
DeadCow
"Jean-François GAZET" a écrit dans le message news:
3f51c5e6$0$288$

La fonction search est définie comme cela : void search(char *s);
Mais si je fais :
hThread1=CreateThread(NULL,0,search,NULL,0,&thread1);
J'ai l'erreur suivante à la compilation :
error C2664: 'CreateThread' : cannot convert parameter 3 from 'void (char
*)' to 'unsigned long (__stdcall *)(void *)'
None of the functions with this name in scope match the target


type
Alors en collant 'unsigned long (__stdcall *)(void *), ça marche.



Ouille ouille ouille. C'est pas bon dutout ça ! Ta fonction search n'a pas
de paramètre de retour, et tu la cast en une fonction qui en a un. Il faut
mannier les cast avec beaucoup de précautions, car avec un cast tu
outrepasse les vérification du compilateur, et par là même tu peut faire de
grosse bêtises. Il vaut mieux que tu respect exactement la signature et que
tu fasse ton cast *dans* la fonction search :

unsigned long search( void * p ) {
char *word (char*)p;

return 0;
}


-- Nicolas Repiquet
Avatar
Arnaud Debaene
Jean-François GAZET wrote:

la fonction search *doit* avoir pour signature :
long __stdcall search(void* param);
C'est bien le cas? Sinon il est fort probable que ton thread ne
démarre pas ou fasse n'importe quoi.



La fonction search est définie comme cela : void search(char *s);
Mais si je fais :
hThread1=CreateThread(NULL,0,search,NULL,0,&thread1);
J'ai l'erreur suivante à la compilation :
error C2664: 'CreateThread' : cannot convert parameter 3 from 'void
(char *)' to 'unsigned long (__stdcall *)(void *)'
None of the functions with this name in scope match the
target type Alors en collant 'unsigned long (__stdcall *)(void *), ça
marche.



Non ca ne marche pas, ou bien si ca marche c'est un coup de chance (le plus
probable est que tu exploses la pile du thread ouvrier sur le retour de la
fonction search). Réécrit la signature de search, ou bien alors écrit une
fonction supplémentaire avec la bonne signature qui appelle elle-même
search.
Quand le compilateur te dit qu'il ne peut pas convertir "machin" en "truc",
c'est qu'il a une bonne raison de le faire, et vouloir lui fermer son clapet
avec un cast sauvage à la C est généralement une *très* mauvaise idée sauf
si tu sais exactement ce que tu fais.

Mais dans ce cas, il semble que la variable globale censée stopper
la recherche n'ait plus d'effet


1) Variable globale --> mauvaise idée. Pourquoi ne pas passer un
pointeur vers les paramètres dont le thread a besoin dans l'argument
de search?



je ne suis pas expert avec les pointeurs. Je ne comprend pas bien
votre question.



Actuellement, d'où vient (et que vaut) le paramètre s de ta fonction
"search" ? Relis la doc de CreateThread, et tu verras que son 4ème paramètre
est passé comme argument à la fonction du thread : tu peux utiliser ce
paramètre pour lui passer ce que tu veux, par exemple un pointeur sur le
flag d'arrêt, ou bien les données à chercher, ....


Comment stopper la recherche avec cette variable globale ?


En la positionnant de manière thread-safe (atomique).



Quel est le code pour cela ?


Impossible à dire ne connaissant pas le type de cette variable et comment tu
l'utilises. Soit tu utilises une CRITICAL_SECTION pour protéger ses accès
(lecture et écriture) dans les deux threads, soit tu utilises
InterlockedIncrement (ou un de ses petits copains) pour la positionner.

Arnaud
MVP - VC
Avatar
Jean-François GAZET
> > La fonction search est définie comme cela : void search(char *s);
> Mais si je fais :
> hThread1=CreateThread(NULL,0,search,NULL,0,&thread1);
> J'ai l'erreur suivante à la compilation :
> error C2664: 'CreateThread' : cannot convert parameter 3 from 'void


(char
> *)' to 'unsigned long (__stdcall *)(void *)'
> None of the functions with this name in scope match the target
type
> Alors en collant 'unsigned long (__stdcall *)(void *), ça marche.

Ouille ouille ouille. C'est pas bon dutout ça ! Ta fonction search n'a pas
de paramètre de retour, et tu la cast en une fonction qui en a un. Il faut
mannier les cast avec beaucoup de précautions, car avec un cast tu
outrepasse les vérification du compilateur, et par là même tu peut faire


de
grosse bêtises. Il vaut mieux que tu respect exactement la signature et


que
tu fasse ton cast *dans* la fonction search :

unsigned long search( void * p ) {
char *word (char*)p;

return 0;
}
-- Nicolas Repiquet



Si je met :
unsigned long search() {...}

J'ai :
cannot convert parameter 3 from 'unsigned long (void)' to 'unsigned long
(__stdcall *)(void *)' :-((
Avatar
DeadCow
"Jean-François GAZET" a écrit dans le message news:
3f51f3e1$0$281$

Si je met :
unsigned long search() {...}



Normal c'est :

unsigned long search( void* ) {}

Ne confond pas 'void' et 'void*', 'void*' représente un pointeur vers une
donnée dont le type n'est pas connue alors que 'void' représente l'absence
de paramètre, ou l'absence de valeur de retour.

J'ai :
cannot convert parameter 3 from 'unsigned long (void)' to 'unsigned long
(__stdcall *)(void *)' :-((



-- Nicolas Repiquet
Avatar
Jean-François GAZET
> > Si je met :
> unsigned long search() {...}

Normal c'est :

unsigned long search( void* ) {}

Ne confond pas 'void' et 'void*', 'void*' représente un pointeur vers une
donnée dont le type n'est pas connue alors que 'void' représente l'absence
de paramètre, ou l'absence de valeur de retour.

> J'ai :
> cannot convert parameter 3 from 'unsigned long (void)' to 'unsigned long
> (__stdcall *)(void *)' :-((



Idem, j'ai toujours l'erreur. J'ai trouvé ceci :
http://www.experts-exchange.com/Programming/Programming_Languages/Q_20573729.html
C'est le même problème et ils le corrigent en castant avec
(LPTHREAD_START_ROUTINE), ça marche, mais c'est surement comme caster avec
unsigned long (__stdcall *)(void *).
Avatar
DeadCow
"Jean-François GAZET" a écrit dans le message news:
3f5202a0$0$281$

Idem, j'ai toujours l'erreur. J'ai trouvé ceci :



Effectivement y a un détail que j'ai oublié : La convention d'appel. La
signature réel c'est ça :


unsigned long WINAPI seach( void* p ) { ... }

ou alors, si tu veut le faire 100% windows ça donne :

DWORD WINAPI seach( LPVOID p ) { ... }

-- Nicolas Repiquet
Avatar
Jean-François GAZET
> > Idem, j'ai toujours l'erreur. J'ai trouvé ceci :
Effectivement y a un détail que j'ai oublié : La convention d'appel. La
signature réel c'est ça :

unsigned long WINAPI seach( void* p ) { ... }
ou alors, si tu veut le faire 100% windows ça donne :
DWORD WINAPI seach( LPVOID p ) { ... }
-- Nicolas Repiquet



Ok, tout marche bien maintenant merci.
Pour info, pour quitter la fenêtre pendant une recherche, je fais un
TerminateThread() dans "case WM_CLOSE".
Avatar
François Müller
"Jean-François GAZET" escribió en el mensaje
news:3f51f3e1$0$281
| Si je met :
| unsigned long search() {...}
|
| J'ai :
| cannot convert parameter 3 from 'unsigned long (void)' to 'unsigned long
| (__stdcall *)(void *)' :-((

Normal, la convention d'appel est incorrecte (manque le __stdcall, sachant
que le __cdecl est pris par défaut sauf instruction contraire comme
paramètre de compilation)

F.
1 2