Savoir, dans une fonction, si on est dans le thread principal

Résolu
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 - 15 oct. 2017 à 10:53
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 - 15 oct. 2017 à 17:49
Bonjour,
J'ai dans mon programme une fonction qui est soit lancée dans un thread asynchrone, soit appelée directement par un menu de la fenêtre principale.

Or le comportement de cette fonction doit dépendre de la méthode d'appel. Ou encore, l'appel direct doit pouvoir savoir comment s'est terminée la fonction. Mais comme cette dernière est également appelée par un Thread.Start(), elle ne peut être que void (à ma connaissance), et donc ne peut pas renvoyer de résultat.

Je voudrais éviter d'utiliser un BackgroundWorker, qui me paraît être un marteau-pilon pour écraser une mouche. Je suppose qu'il existe un moyen de récupérer un identificateur du thread courant et celui du thread principal, ou de savoir si on est dans un thread asynchrone ou non. En fonction de cela, je pourrais effectuer dans ma fonction les actions nécessaires à l'appel direct.

Bien sûr, je pourrais faire deux fonctions distinctes, mais j'ai horreur de dupliquer du code, pour des raisons de maintenance évidentes.

Une solution ?

7 réponses

Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
15 oct. 2017 à 11:30
Bonjour

un peu de code pour mieux visualiser s'il te plait.
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
15 oct. 2017 à 12:31
Bonjour Whismeril. Toujours là en permanence, à ce que je vois.

Voila le code. Je ne mets pas tout, sinon ce sera difficilement lisible en raison de son volume.

Principe : recherche d'une mise jour en tâche de fond par lecture d'un fichier web donnant la dernière version. Si une mise à jour est trouvée, la fonction continue en téléchargeant et lançant le package d'installation.
- Lors du démarrage de l'application, la fonction est lancée dans un thread asynchrone. S'il n'y a pas de mise à jour à faire, ou une erreur de connexion, la fonction se termine "sans bruit". L’utilisateur n'est pas informé.
- Lorsque l'utilisateur clique sur le menu "Rechercher une mise à jour", et qu'il y en a pas ou qu'il y a une erreur de connexion, il faudrait pouvoir afficher un message "Pas de mise à jour disponible" ou "Erreur de connexion".

Voir les commentaires entre /* --- et --- */


Dans l'évènement load de la feuille principale :
private void wMain_Load(object sender, EventArgs e)
{
[...]
    // Lancement de la recherche de mise à jour
    Thread UpdSearch = new Thread(new ThreadStart(DoUpdSearch));
    UpdSearch.Start();
}

Dans le menu "Rechercher une mise à jour" :
private void mnuHelpUpdateSearch_Click(object sender, EventArgs e)
{
    DoUpdSearch();
}

Et le code partiel de la fonction :
public static void DoUpdSearch()
{
    string sCurrentVersionString = Application.ProductVersion;
    string sCode;
    using (WebClient HttpClient = new WebClient())
    {
        try
        {
            sCode = HttpClient.DownloadString(mksHttpBase + Application.ProductName + ".version.txt");
        }
        catch { return; }
        HttpClient.Dispose();
    }
/* --- Ici, dans le cas d'une erreur (fichier non dispo, pas de connexion), 
il faut qu'il y ait un message dans le cas de l'appel par menu, 
mais pas dans le cas d'un thread séparé. --- */

    Regex Rx = new Regex(@"([0-9]+)\.([0-9]+)\.([0-9]+)");
    Match found = Rx.Match(sCode);

    if (found.Success)
    {
        string[] sCurVersionArray = Application.ProductVersion.Split('.');
        float fCurVersion =
            float.Parse(sCurVersionArray[0]) +
            float.Parse(sCurVersionArray[1]) / 1000 +
            float.Parse(sCurVersionArray[2]) / 1000000;

        string sNewVersion = found.Groups[0].Value;
        float fNewVersion =
            float.Parse(found.Groups[1].Value) +
            float.Parse(found.Groups[2].Value) / 1000 +
            float.Parse(found.Groups[3].Value) / 1000000;

        if (fNewVersion <= fCurVersion)
            return;
/*  --- Ici, dans le cas du return, il faut qu'il y ait un message 
dans le cas de l'appel par le menu, mais pas dans le cas d'un 
thread séparé.  --- */

[...]
/* --- Ici le code télécharge et installe le package, avec dialogue 
avec l'utilisateur, donc comportement identique dans les deux cas --- */
}
0
NHenry Messages postés 15113 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 22 avril 2024 159
15 oct. 2017 à 12:56
Si tu as besoin de l'appeller avec un retour void à un moment et d'avoir un retour à un autre, la solution la plus simple consiste en une fonction qui retourne toujours un résultat et quand tu veux un void, tu créé juste une méthode qui appelle la fonction, du genre :

MyType MaFonction(){}

void MaFonctionSansRetour(){MaFonction();}

0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
15 oct. 2017 à 13:23
Ou alors tu mets un paramètre dans ta signature

 public static void DoUpdSearch(bool ClickUtilisateur = false)
{
...
if (ClickUtilisateur)
 MessageBox.Show("Le message");
...





private void mnuHelpUpdateSearch_Click(object sender, EventArgs e)
{
    DoUpdSearch(true);
}


pas de changement pour l'autre appel
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
15 oct. 2017 à 16:23
Ca, c'est évident et j'avais bien sûr déjà essayé.

Mais le compilateur n'est pas du tout d'accord dans la création du thread :
Dans la ligne :
Thread UpdSearch = new Thread(new ThreadStart(DoUpdSearch));

il me dit :
Aucune surcharge pour 'DoUpdSearch' ne correspond au délégué 'ThreadStart'	D:\Documents\_Portable\Csharp\SynchroDir 3\Sources\wMain.cs


Mais comme ça m'a fait réfléchir à un moyen de passer outre, j'ai cette fois pensé à créer une surcharge de ma fonction. Et ça fonctionne.
L'appel par le thread n'est pas modifié. L'appel par le menu comporte le paramètre true qui déclenche les messages.

Voici le code de la fonction et sa surcharge :
// Recherche de mise à jour. Cette fonction est exécutée dans un thread à part et lancée par wMain_Load
public static void DoUpdSearch()
{
    DoUpdSearch(false);
}

public static void DoUpdSearch(bool direct = false)
{
    string sCurrentVersionString = Application.ProductVersion;
    string sCode;
    using (WebClient HttpClient = new WebClient())
    {
        try
        {
            sCode = HttpClient.DownloadString(mksHttpBase + Application.ProductName + ".version.txt");
        }
        catch
        {
            HttpClient.Dispose();
            if (direct)
                MessageBox.Show("Le fichier de définition de version n'a pu être trouvé.\n" + 
                                "Vérifiez éventuellemnt votre connexion Internet.",
                                "Mise à jour", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }
        HttpClient.Dispose();
    }

    Regex Rx = new Regex(@"([0-9]+)\.([0-9]+)\.([0-9]+)");
    Match found = Rx.Match(sCode);

    if (found.Success)
    {
        string[] sCurVersionArray = Application.ProductVersion.Split('.');
        float fCurVersion =
            float.Parse(sCurVersionArray[0]) +
            float.Parse(sCurVersionArray[1]) / 1000 +
            float.Parse(sCurVersionArray[2]) / 1000000;

        string sNewVersion = found.Groups[0].Value;
        float fNewVersion =
            float.Parse(found.Groups[1].Value) +
            float.Parse(found.Groups[2].Value) / 1000 +
            float.Parse(found.Groups[3].Value) / 1000000;

        if (fNewVersion <= fCurVersion)
        {
            if(direct)
                MessageBox.Show("Aucune mise à jour disponible.",
                                "Mise à jour", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }
[...] /* Le reste du traitement est inchangé puisqu'il y a toujours dialogue */
}


Merci pour le support 7/24.
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
15 oct. 2017 à 16:38
Ha le paramètre facultatif ne plaît pas au thread...
Alors tu peux aussi passer le paramètre
https://stackoverflow.com/questions/1195896/threadstart-with-parameters
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
15 oct. 2017 à 16:40
En aparté, pour ta regex, tu peux remplacer [0-9] par \d
0
MGD Software Messages postés 186 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 avril 2022 2
15 oct. 2017 à 17:34
La solution ne m'est plus nécessaire puisqu'une simple surcharge suffit dans mon cas, mais je vais en garder la trace pour le jour où j'aurais vraiment des paramètres à passer à un thread.

J'avais cherché sur le net comment passer des paramètres à un thread, mais je n'ai trouvé que des usines à gaz, bien loin de la solution fournie par JaredPar.

Mais auparavant, il faut que je comprenne vraiment comment fonctionnent les expressions lambda. Je vais relire la page 198 de mon bouquin, que j'ai manifestement survolée d'un peu trop haut.

Merci pour le lien.

>> En aparté, pour ta regex, tu peux remplacer [0-9] par \d
Oui, je sais, mais c'est une vieille habitude prise dans les langages qui ne connaissent pas \d. Surtout que dans la plupart des cas, on y ajoute
a-zA-Z... Et pour cette fonction, je ne recherche pas la performance.
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
Modifié le 15 oct. 2017 à 17:49
Je ne pense pas que ce soit plus performant, c’est juste plus rapide à écrire.

[0-9a-zA-Z] => \w, enfin presque, il accepte le . aussi
0
Rejoignez-nous