Bonjour à tous,
Je voudrais vous soumettre un problème auquel je suis confronté depuis une semaine.
Je suis en train de concevoir un programmes qui inclut un module de communication FTP.
J'ai décidé d'utiliser le composant TIdFtp de Indy 10 (que j'ai mis à jour vers la dernière version à partir du site officiel).
Ce composant offre la possibilité de récupérer et parser automatiquement le contenu d'un serveur via la méthode List.
Toutefois, utiliser List dans le thread principal a le principal désavantage de bloquer le processus, ce qui est quelque peu gênant vu que certains de mes serveurs de test peuvent prendre jusqu'à 5 minutes pour répondre à LIST.
C'est pourquoi je voulais mettre l'appel à List dans un thread séparé. Je manque de connaissance concernant les threads (c'est en fait la première fois que j'utilise des threads dans un projet majeur), et de ce fait je ne suis pas sûr que mon implémentation de List dans ce contexte soit appropriée. J'ai également tenté d'utiliser TIdAntiFreese, mais cela ne semble pas fonctionner.
Le problème avec ce thread est que, chaque fois que je démarre le thread à partir de la procédure mère, j'obtiens une Violation d'accès (lecture à l'adresse "00000004").
Ce qui suit est le code principal de mon thread, qui a pour seul but d'effectuer List.
Vu que le composant TIdFtp n'est pas hébergé dans ce thread, j'ai utilisé Synchronize pour éviter les problèmes d'interblocage (ou du moins, c'est supposé l'éviter).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 constructor TFtpListerThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); FreeOnTerminate := false; Priority := tpNormal; end; procedure TFtpListerThread.DoAction; begin if (FtpTrafficBox.teststatus = 0) then // to make sure that the thread does only one execution begin try FtpTrafficForm.FtpModule.List(nil, '', true); // the most important line of this thread except FtpTrafficBox.teststatus := 2; // teststatus evaluated to 2 in case of failure end; if (FtpTrafficBox.teststatus = 0) then FtpTrafficBox.teststatus := 1; // on success, evaluated to 1 end; end; procedure TFtpListerThread.Execute; begin while not Terminated do Synchronize(DoAction); end;
A ce que je sache, il n'y a aucun moyen de retourner facilement une valeur à la sortie du thread, j'ai donc utilisé une réponse par variable globale pour indiquer au processus appelant que List a été effectué. Je suis certain qu'il y a de meilleurs moyens de faire ça ; je suis ouvert à toute suggestion.
La procédure appelante du thread principal est la suivante :
Bien que le debuggueur n'ait pas été très clair sur l'origine du crash, je suis pratiquement sûr que cela se produit quand le thread tente d'effectuer List.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 teststatus := 0; // Re-initializes the global variable FtpListerThread.Resume; // Starts thread while (teststatus = 0) do begin sleep(10); Application.ProcessMessages; // Keep process messages while it awaits for the end of the thread (not very elegant, I know) end; FtpListerThread.Suspend; // Stops the thread when List has finished if (teststatus = 2) then begin // Procedures in case of failure end;
De plus lorsque je tente d'éviter l'appel au thread en mettant List dans une structure try-except, cela est effectué sans aucun problème, excepté pour le problème de lag que je souhaitais éviter avec le thread.
De nombreuses personnes ont reporté des problèmes similaires qui ont été corrigés dans une mise à jour de Indy 10 (maj qui concernait une modification d'un Integer vers un Int64 ou qq chose comme ça). Mettre à jour le Indy 10 original inclus dans Delphi n'a pas résolu le problème.
Je pense que tout a été dit. J'espère que vous serez en mesure de me donner un coup de main dans cette histoire.
Si vous avez besoin d'informations complémentaires, ou si vous voulez me taper sur les doigts pour mon code (dégeu ?), n'hésitez surtout pas.
Merci d'avance pour votre aide.
Steph.
Partager