2010-12-03 7 views
2

J'essaie de travailler avec Threadding et il me semble que c'est étrangement difficile (je le fais probablement mal).C# - Les threads peuvent-ils se comporter comme BackgroundWorkers (winForms)?

Je veux charger un fichier à l'intérieur d'un BackgroundWorker et pendant ce temps, "envoyer" chaque nouvelle ligne à un thread distinct (pas bgWorker). J'utilise BlockingCollection et Add() chaque ligne, puis je veux Take() eux et les traiter dans un autre thread.

Maintenant, tout est simple avec le BgWorker; mais pourquoi est-il impossible (n'est-ce pas?) de simplement déclarer un nouveau fil dans Form1.cs et de le faire fonctionner comme le BgWorker? En d'autres termes, pourquoi devez-vous créer un WorkerClass distinct (http://msdn.microsoft.com/en-us/library/7a2f3ay4(VS.80).aspx)? Je demande cela parce que, vous pouvez accéder à votre BlockingCollection amende à partir de BackgroundWorker, mais vous ne pouvez pas le faire à partir d'une classe distincte WorkerClass (car il s'agit d'une classe distincte plaine vanille). (Alors quel est le point de la BlockingCollection alors si vous ne pouvez pas l'utiliser pour ce que cela signifie?)

De plus, BgWorkers a un événement/méthode ReportProgress(...). Pour autant que je sache, si vous utilisez cet exemple msdn, vous n'avez pas squat dans votre Thread.

Qu'est-ce qui me manque ici? S'il vous plaît aider.


PS: Avant de sauter et de me dire que c'est en aucune façon plus efficace d'envoyer des lignes à un autre fil, sachez que je fais cela comme un exercice d'apprentissage. Essayer de comprendre comment les Threads fonctionnent en C# et comment vous synchronisez/communiquez entre eux (et/ou bgWorkers).

+0

Si vous voulez apprendre comment fonctionnent les threads, n'utilisez pas BGW, cela vous évitera trop de problèmes. –

+1

Si vous utilisez BlockingCollection, vous êtes sur Fx4 et vous devriez regarder dans Tâches (TPL) plutôt que des discussions. –

+0

@ Henk; Mec. Merci. (Je vais encore regarder dans les threads mais) Merci de me parler de l'existence de 'System.Threading.Tasks'. Que le dossier montre que c'est "ce que je voulais" (BlockingCollection + Tasks): http://www.codethinked.com/post/2010/02/08/BlockingCollection-and-IProducerConsumerCollection.aspx – Spectraljump

Répondre

2

Pour répondre à votre question dans le titre, oui fils "normaux" peuvent agir comme BackgroundWorker threads. Vous avez juste à créer plus de code de câblage vous-même.

J'ai écrit une application simple pour analyser ma collection de musique en utilisant un fil créé manuellement. Le corps principal du thread est une méthode qui boucle sur tous les dossiers sous une racine spécifiée et déclenche un événement chaque fois qu'il rencontre un dossier qui contient des fichiers mp3.

Je souscris à cet événement dans la forme principale de mon application et mettre à jour un DataGridView avec les nouvelles informations.

Ainsi, le fil est lancée par le code suivant:

this.libraryThread = new Thread(new ThreadStart(this.library.Build)) { IsBackground = true }; 

// Disable all the buttons except for Stop which is enabled 
this.EnableButtons(false); 

// Find all the albums 
this.libraryThread.Start(); 

La méthode fournie ThreadStart fait un peu de ménage, puis appelle la méthode qui fait le travail:

private void FindAlbums(string root) 
{ 
    // Find all the albums 
    string[] folders = Directory.GetDirectories(root); 
    foreach (string folder in folders) 
    { 
     if (this.Stop) 
     { 
      break; 
     } 

     string[] files = Directory.GetFiles(folder, "*.mp3"); 
     if (files.Length > 0) 
     { 
      // Add to library - use first file as being representative of the whole album 
      var info = new AlbumInfo(files[0]); 
      this.musicLibrary.Add(info); 
      if (this.Library_AlbumAdded != null) 
      { 
       this.Library_AlbumAdded(this, new AlbumInfoEventArgs(info)); 
      } 
     } 

     this.FindAlbums(folder); 
    } 
} 

Lorsque cette méthode termine un événement final LibraryFinished est tiré.

Je souscris à ces événements sous la forme principale:

this.library.Library_AlbumAdded += this.Library_AlbumAdded; 
this.library.Library_Finished += this.Library_Finished; 

et ces méthodes ajouter le nouvel album à la grille:

private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e) 
{ 
    this.dataGridView.InvokeIfRequired(() => this.AddToGrid(e.AlbumInfo)); 
} 

et terminer (qui boutons etc. réactive les) :

private void Library_Finished(object sender, EventArgs e) 
{ 
    this.dataGridView.InvokeIfRequired(() => this.FinalUpdate()); 
} 

Comme vous pouvez le voir c'est beaucoup de travail qui serait beaucoup plus simple si je l'habitude un BackgroundWorker.

+0

Ceci est un exemple très utile. (explique ma question «comment les événements vous aideraient-ils»). Je ne comprends pas ce que 'this.library.Build' est cependant. La bibliothèque est-elle une classe? ou quoi? – Spectraljump

+0

@Twodordan - C'est une classe que j'ai créée et qui représente une médiathèque. Le nom pourrait être mieux je suppose.La méthode 'FindAlbums' réside dans cette classe. – ChrisF

+0

Merci beaucoup. Tout s'explique maintenant :) – Spectraljump

3

Répondre spécifiquement pourquoi travailler avec des fils est plus difficile que de travailler avec un travailleur de fond ....

Le BackgroundWorker est en fait une méthode pour créer un autre fil enveloppé dans un emballage plus facile à utiliser. La raison de travailler directement avec les threads est plus difficile parce que c'est plus proche de la réalité. Pour une comparaison similaire, l'utilisation de System.Net.Mail pour envoyer un email est simplement une manière simplifiée de créer des connexions de socket, etc ... Sous le capot, les classes System.Net.Mail font le travail détaillé. De même, sous le capot, le BackgroundWorker fait le travail détaillé de traiter les discussions.

En fait, le documentaiton MSDN pour l'objet BackgroundWorker commence comme ceci:

classe BackgroundWorker Mise à jour: Septembre 2010

exécute une opération sur un thread séparé .

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Donc, si la classe BackgroundWorker est censé faciliter l'enfilage plus facile, pourquoi les gens veulent travailler avec des fils directement? En raison du problème que vous rencontrez. Parfois, le «wrapper amical» conduit à une perte de contrôle fin.

Edition - a ajouté

Qu'est-ce que vous demandez au sujet dans les commentaires est la synchronisation des threads.Cet article couvre assez bien.

http://msdn.microsoft.com/en-us/magazine/cc164037.aspx

et cet article répond à "communiquer entre les threads" explicitement.

http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic63233.aspx

+0

Eh bien c'est génial. " La vraie chose "ne me semble pas être un avantage sur le BgWorker de la même chose-seulement-mieux-et-milles-plus facile. Peu importe, comment pouvez-vous (pouvez-vous?) Utiliser BlockingCollection sur les threads normaux? – Spectraljump

+0

Le problème que j'ai est que je suis capable de communiquer bien entre BgWorkers et je ne vois pas de façon directe/spécifique de le faire avec des Threads réguliers. – Spectraljump

+0

@Twodordan - déclencher un événement avec votre objet comme paramètre . – ChrisF

Questions connexes