cs_Bidou
Messages postés5487Date d'inscriptiondimanche 4 août 2002StatutMembreDernière intervention20 juin 2013
-
6 mai 2005 à 10:30
cs_Bidou
Messages postés5487Date d'inscriptiondimanche 4 août 2002StatutMembreDernière intervention20 juin 2013
-
10 mai 2005 à 08:09
Bonjour,
Bon je suis pas encore tout à fait au point avec les Threads. La question est certainement pas très compliquée.
J'ai une forme qui contient un bouton "search". Quand on clique dessus, le programme commence à faire une recherche qui peut durer un certain temps (tout dépend).
Avant, tout mon code (Recherche + Affichage de la recherche) se faisait dans l'event click de mon bouton "search". Le problème était évidemment que si la recherche prennait du temps, rien ne se passait pendant plusieurs secondes (et la fenetre de recherche était "bloquée", on ne peut plus la bouger).
J'ai donc créee une méthode Search, que je démarre dans l'event click de mon bouton avec un thread, et avant ça je met un petit message dans un statusBar pour avertir l'utilsateur que la recherche a commencée, ça donne qqch comme :
// Search recherche et affiche le résultat
myStatusBar.Text = "Recherche en cours... patientez...";
Thread threadSearch = new Thread(new ThreadStart(Search));
threadSearch.Start();
Le problème c'est que le code suivant me retourne une erreur, il me dit qu'un contrôl créee par un thread ne peut pas être parenté à un control d'un thread different. C'est normal, puisque dans la méthode search, je recherche et ensuite j'affiche ma recherche (dans un datagrid). Donc je me dis que dans ma méthode Search, je dois juste faire la recherche, et le reste dans l'event de mon bouton "search" :
// Cette fois, search ne fait que la recherche !
myStatusBar.Text = "Recherche en cours... patientez...";
Thread threadSearch = new Thread(new ThreadStart(Search));
threadSearch.Start();
AfficheLesResultats();
J'arrive à un autre problème : AfficheLesResultats se sert évidemment d'une variable globale (une collection) qui contient les résultats. Mais cette variable n'est bien sûre pas initialisée tant que la méthode Search() n'a pas été executée. Donc j'ai un null pointer exception. J'ai essayé un threadSearch.Join() juste avant la méthode AfficheLesResultats(), la ça ne plante plus, mais je n'ai rien de plus qu'au début (la form est figée, on peut plus la bouger et c'est évidemment pas le but).
J'ai déjà rencontré ce problème pleins de fois, et j'ai jamais réussi à régler ça proprement, quelqu'un peut-il m'aider? Merci !
// Clique effectué sur le bouton de recherche
private void btnSearch_Click(object sender, System.EventArgs e)
{
this.statusBarSearch.Text = "Recherche en cours... patientez...";
// Démarre la recherche dans un nouveau thread
Thread t = new Thread(new ThreadStart(Searching));
t.IsBackground = true;
t.Start();
}
// Commence la recherche
private void Searching()
{
// La collection qu'il faut remplir et qui va être affichée dans le datagrid
MoviesCollection moviesCol = null;
// J'ai ici un object Search que j'ai conçu qui me permet d'effectuer mes
// recherches selon certains critères
Search s = new Search(_variable);
/* Ensuite un code assez long pour rechercher, voici un aperçu simplifié */
moviesCol = s.Go();
// On passe la collection (qui est la réponse de la recherche) au delegate
// que j'ai crée, qui prend justement une telle collection en argument :-)
object[] mCol = { moviesCol };
myDataGrid.BeginInvoke(new SearchDelegate(Invocation), mCol);
}
// Appel asynchrone, on reçoit en argument l'object passé lors de l'appel de BeginInvoke
private void Invocation(MoviesCollection moviesCol)
{
// Ici je fais qqe traitement sur ma collection
// Puis je remplis mon datagrid avec ma collection
}
Ceci dit il reste encore un miniscule problème : dans la méthode Invocation, selon le résultat de la recheche, je change la taille de ma form ou se trouve le datagrid (je l'agrandis si y'a beaucoup de résultat, pour que ce soit plus conviviale). Ca semble marcher.
Maintenant, puisque tout est fait comme je le souhaite, je peux bouger ma forme comme j'en ai envie pendant la recheche, ça bloque plus comme avant (c'était le but :-) ). Si je relache la forme AVANT que le code passe par la méthode Invocation, pas de problème, par contre si je bouge ma forme à ce moment, alors il semble que le code ne soit pas exécuter (la forme ne s'agrandit pas).
Lutinore
Messages postés3246Date d'inscriptionlundi 25 avril 2005StatutMembreDernière intervention27 octobre 201241 6 mai 2005 à 13:44
Pour eviter que ta forme "freeze" tu peux faire plus simple:
private void searchButton_Click( object sender, System.EventArgs args )
{
searchButton.Enabled = false; // Pour ne pas entrer a nouveau dans la fonction
while ( !found )
{
// Ici tu recherches etape par etape pas tout d'un coup
Application.DoEvents( ); // Traite les evenements
}
searchButton.Enabled = true;
}
Sinon pour faire patienter un thread utilise l'expression "lock"
Vous n’avez pas trouvé la réponse que vous recherchez ?
Lutinore
Messages postés3246Date d'inscriptionlundi 25 avril 2005StatutMembreDernière intervention27 octobre 201241 7 mai 2005 à 16:54
Je persiste a dire que tu pouvais te passer d'un second thread en utilisant la methode "DoEvents" a intervalles reguliers pendant la recherche pour ne pas freezer ta forme . Sinon as tu essaye d'initialiser ta collection avec des valeurs bidons ( a zero ) avant de lancer ton second thread ( sans la methode join ) puis de reactualiser ta collection avec les vrais valeurs une fois que ton thread est stoppe ( ThreadState.Stopped ).
Si tu as un probleme de synchronisation alors utilise le mot cle "lock" pour empecher un second thread de modifier une partie de code avant que le premier thread est fini son boulot, mais la tu vas encore avoir un probleme de blocage de ta forme.
Tu peux aussi utiliser la fonction "join" avec un parametre de temps "join( 20 )" et la tu affiches tes resultats petis a petits, pas tout d'un coup ! comme la commande Rechercher de windows dans le menu demarrer !
Le mot cle "volatile" peut aussi etre utile dans une application multithread.
cs_Bidou
Messages postés5487Date d'inscriptiondimanche 4 août 2002StatutMembreDernière intervention20 juin 201361 9 mai 2005 à 12:18
A vrai dire je n'ai pas encore réussi
Petite question sur ton code : A quel object appartient ta méthode BeginInvoke ?
(et accessoirement, t.IsBackground et t.SetApartmentState(ApartmentState.STA) servent à quoi exactement ?).
MorpionMx
Messages postés3466Date d'inscriptionlundi 16 octobre 2000StatutMembreDernière intervention30 octobre 200857 9 mai 2005 à 12:37
Le BeginInvoke est appelé depuis la form qui sert de SplashScreen, donc j'imagine que c'est une méthode de la classe Control
Pour ce qui est du IsBackground, c'est pour spécifier que c'est un
thread d'arriere plan, donc qui n'empeche pas un processus de s'arreter.
Et le SetApartmentState (qui est une méthode 2.0 en fait, mais dans la
version 1.1, on peut acceder a la propriété ApartmentState), bah je te
renvoies a l'aide du framework parce que comme ca c'est dur a resumer
(et a vrai dire, ca reste un peu flou pour moi)