IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Thread bloquant, pourquoi ?


Sujet :

C#

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 32
    Par défaut Thread bloquant, pourquoi ?
    Voilà mon code qui doit effectuer une capture d'une page web :

    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    public class WebScreenShooter 
    { 
    //adresse web de la page à prendre en photo 
    private string url = null; 
    //taille de l'image 
    private Size bmpSize; 
    //image contenant la page web 
    private Bitmap bmp = null; 
    public Bitmap Image { get { return bmp; } } 
    //objet pour la synchronisation des threads 
    private ManualResetEvent mre = new ManualResetEvent(false); 
    //timeout en secondes 
    private int timeout = 5; 
     
    #region Constructeur 
    public WebScreenShooter(string url, Size bmpSize) 
    { 
    this.url = url; 
    this.bmpSize = bmpSize; 
    } 
    #endregion 
     
    #region TakeScreenShot 
    public Bitmap TakeScreenShot() 
    { 
    //on crée notre thread qui va s'occuper de la capture d'image 
    Thread t = new Thread(new ThreadStart(_TakeScreenShot)); 
    //il est important de spéicifer que c'est un Single Thread Apartement 
    //afin de pouvoir instancier l'objet WebBrowser 
    t.SetApartmentState(ApartmentState.STA); 
     
    //on démarre notre thread 
    t.Start(); 
    //on attent qu'il aille terminer 
    mre.WaitOne(); 
    //on termine le thread qui a capturer l'image 
    t.Abort(); 
    //on retourne l'image de la page web 
    return bmp; 
    } 
    #endregion 
    private void _TakeScreenShot() 
    { 
    //on instancie un objet webBrowser 
    WebBrowser webBrowser = new WebBrowser(); 
    //on prend le temps pour pouvoir gérer le timeout 
    DateTime time = DateTime.Now; 
    webBrowser.ScriptErrorsSuppressed = true; 
    webBrowser.ScrollBarsEnabled = false; 
    //on navigue à l'url spécifiée par l'utilisateur 
    webBrowser.Navigate(url); 
    //on attend que la page aille finit de se charger 
    //avant de capturer son image 
    webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted); 
     
    //une petite boucle pour que le thread ne se termine pas tout de suite 
    //on s'assure qu'on a pas dépassé le timeout 
    while (true) 
    { 
    Thread.Sleep(100); 
    TimeSpan deltaTime = DateTime.Now - time; 
    if (deltaTime.Seconds >= timeout) mre.Set(); 
    Application.DoEvents(); 
    } 
     
     
    } 
    private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
    { 
    WebBrowser webBrowser = (WebBrowser)sender; 
    webBrowser.ClientSize = bmpSize; 
    webBrowser.ScrollBarsEnabled = false; 
     
    bmp = new Bitmap(webBrowser.Bounds.Width, webBrowser.Bounds.Height); 
     
    webBrowser.BringToFront(); 
    webBrowser.DrawToBitmap(bmp, webBrowser.Bounds); 
    webBrowser.Dispose(); 
    if (mre != null) mre.Set(); 
    } 
     
    public void Dispose() 
    { 
    if (bmp != null) this.bmp.Dispose(); 
    //if (webBrowser != null) this.webBrowser.Dispose(); 
    } 
    }
    Ca fait son job, mais en bloquant le reste de l'application. Quelqu'un pourrait m'expliquer pourquoi, puis comment modifier ce code pour qu'il ne bloque plus l'appli quand je l'appelle ?

  2. #2
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Par défaut
    A cause de cette ligne :
    Tu dis explicitement qu'il faut mettre en attente le thread principal tant que le thread secondaire n'est pas terminé.
    Besoin d'un MessageBox amélioré ? InformationBox pour .NET 1.1, 2.0, 3.0, 3.5, 4.0 sous license Apache 2.0.

    Bonnes pratiques pour les accès aux données
    Débogage efficace en .NET
    LINQ to Objects : l'envers du décor

    Mon profil LinkedIn - MCT - MCPD WinForms - MCTS Applications Distribuées - MCTS WCF - MCTS WCF 4.0 - MCTS SQL Server 2008, Database Development - Mon blog - Twitter

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 32
    Par défaut
    Oui, je m'en doutais.
    Comment je peux modifier mon code pour qu'il ne bloque pas dans ce cas ?

    Pour être plus précis : Mon application gère une liste d'url. Pour chaque élément de cette liste, je veux générer une image, mais pour un seul élément à la fois.

    Si je supprime les références à mon instance mre, la création de la miniature du deuxième élément commence sans attendre que la première ait été générée.

    Donc le but, c'est que le thread ne se termine pas avant que la miniature soit prête, mais en même temps qu'il ne gèle pas le reste de l'application (pendant l'exécution de ce code, si je clique sur mon winform pour faire autre chose, le winform devient blanc, le curseur devient wait, et la barre de titre indique le nom de mon appli + "Ne répond plus")

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 32
    Par défaut
    A titre d'information, j'ai essayé de changer la priorité du thread ainsi que de le spécifier en tant que tâche de fond, mais rien n'y fait, il bloque toute l'application...

  5. #5
    Invité de passage
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    1
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 1
    Par défaut information de base
    La question que je me pose est pourquoi tu pars un thread puis que tu l'attend immediatement ? Le thread est inutile ici puisque c'Est la même choses que si tu appellais une fonction synchronisée directement... (attente de la fin de son exécution)

    l'impression que j'ai c'Est que ton application gèle quand tu appel TakeScreenShot, puisque que tu attend sa fin... Essais d'appeller cette fontion a partir d'un thread ou bien un delegate/callback... (N'importe quoi de non synchro. En gros, ton application doit etre capable de continuer de rouler même si tu lui demande de prendre un screenshot (a moins que ca soit voulu pour éviter des modifications inatendus...)

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 32
    Par défaut
    Le problème est un peu plus complexe parce que j'appelle cette méthode depuis un BackgroundWorker. Or, la création d'un objet WebBrowser nécessite Single Thread Apartment (alors que manifestement le BackgroundWorker est Multi Thread Apartment)

    Mais j'ai résolu mon problème ce matin par l'utilisation de Windows Live Writer : http://windowslivewriter.spaces.live.com/

    En effet, une fois installé, on a accès à une Dll très sympathique : WindowsLive.Writer.Api.dll, elle-même donnant accès à un objet encore plus sympathique : HtmlScreenCapture.

    Du coup, faire une capture d'un site web est aussi simple que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    HtmlScreenCapture hsc = new HtmlScreenCapture(uri, 1200);
    Image image = hsc.CaptureHtml((int)(timeout * 1000));
    J'ai trouvé cette solution sur je ne sais plus quel blog (j'avais les yeux explosés par mes recherches ^^)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Thread Bloquant & TcpClient
    Par Invité dans le forum Windows Presentation Foundation
    Réponses: 3
    Dernier message: 04/09/2010, 17h42
  2. [MFC] Thread bloquant et sockets
    Par wogkiller dans le forum Threads & Processus
    Réponses: 8
    Dernier message: 09/06/2008, 15h37
  3. Synchronize bloquant dans un thread
    Par bencot dans le forum Langage
    Réponses: 3
    Dernier message: 20/08/2004, 16h42
  4. [Threads] Sortir d'une fonction bloquante
    Par guejo dans le forum MFC
    Réponses: 19
    Dernier message: 17/08/2004, 14h12
  5. [API] Communication série NON-bloquante : OVERLAPPED/Thread
    Par Rodrigue dans le forum C++Builder
    Réponses: 2
    Dernier message: 07/11/2003, 13h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo