2010-11-28 42 views
1

J'ai une classe WorkQueue, il suffit de prendre note sur le DoNext() pour le moment, le reste sont principalement des aides. Fondamentalement, WorkQueue est juste une file d'attente de WorkItems. DoNext() est responsable de "Démarrage d'un workItem en attente avec un travailleur en arrière-plan libre". Notez également qu'il définira la propriété WorkItem.Worker.Besoin d'aide débogage pourquoi la propriété n'est pas définie/null

public class WorkQueue<Tin, Tout> : 
    INotifyCollectionChanged, IEnumerable<WorkItem<Tin, Tout>> 
{ 
    public bool DoNext() 
    { 
     // check if any work left in queue 
     WorkItem<Tin, Tout> item = GetWork(); 
     if (item != null) 
     { 
      // check if any free workers 
      BackgroundWorker worker = GetWorker(); 
      Debug.WriteLine(
       "[WorkQueue.DoNext] Setting Worker to WorkItem: " + worker); 
      item.Worker = worker; 
      if (worker != null) 
      { 
       worker.RunWorkerAsync(item); 
       return true; 
      } 
     } 
     return false; 
    } 
    public void AddWork(WorkItem<Tin, Tout> item) 
    { 
     _queue.Add(item); 
     RaiseCollectionChanged(
      new NotifyCollectionChangedEventArgs(
       NotifyCollectionChangedAction.Add, item)); 
    } 

    public WorkItem<Tin, Tout> GetWork() 
    { 
     return (from i in _queue 
       where i.Status == WorkStatus.Pending 
       select i).FirstOrDefault();; 
    } 

    public BackgroundWorker GetWorker() 
    { 
     return (from worker in _workers 
       where worker.IsBusy == false 
       select worker).FirstOrDefault(); 
    } 
} 

Le problème que j'ai est quand je fais quelque chose comme ci-dessous,

foreach (string filename in fileNames) { 
    UploadQueue.AddWork(new WorkItem<string, UploadedImage>(filename)); 
    UploadQueue.DoNext(); 
} 

UploadQueue est un WorkQueue<string, UploadedImage>. Le 1er (premier seulement) DoNext(), le WorkItem.Worker est nul. Je le sais parce que mon bouton Annuler lié à WorkItem.CancelCommand est désactivé. Lors du débogage, j'ai découvert que la raison en était que le worker est nul.

_cancelCommand = new RelayCommand(...() => 
{ 
    // Returns true if WorkItem is being processed with a worker that supports 
    // cancellation or if the WorkItem is still Pending 
    // False if otherwise, eg. already completed, cancelled etc 
    if (Status == WorkStatus.Processing) 
    { 
     if (_worker != null && _worker.WorkerSupportsCancellation) 
      return true; 
    } else if (Status == WorkStatus.Pending) { 
     return true; 
    } 
    return false; 
}); 

La solution est de déplacer le DoNext() hors de la boucle,

foreach (string filename in fileNames) 
    UploadQueue.AddWork(new WorkItem<string, UploadedImage>(filename)); 
UploadQueue.DoNext(); 

mais ce qui est le problème avec l'intérieur, pourquoi est-travailleur défini sur null? Si son null, à partir de la clause if, le BackgroundWorker ne devrait pas démarrer?

if (worker != null) 
    worker.RunWorkerAsync(item); 

Video Demonstrating the Problem

+0

ce n'est pas comment j'utiliser travailleurs de fond ... –

+1

Quand la vérification de l'état du bouton est-elle effectuée? Et où s'inscrit _cancelCommand? – Doggett

+0

Juste une suggestion, avez-vous pensé à utiliser des tâches à la place? –

Répondre

1
public BackgroundWorker GetWorker() 
{ 
    return (from worker in _workers 
      where worker.IsBusy == false 
      select worker).FirstOrDefault(); 
} 

si tous les travailleurs sont occupés, cette fonction retourne null;

foreach (string filename in fileNames) 
    UploadQueue.AddWork(new WorkItem<string, UploadedImage>(filename)); 
    UploadQueue.DoNext(); 

UploadQueue.DoNext() exécutée plusieurs fois

foreach (string filename in fileNames) 
    UploadQueue.AddWork(new WorkItem<string, UploadedImage>(filename)); 
UploadQueue.DoNext(); 

UploadQueue.DoNext() exécutées une fois.

Ensuite, il est tout à fait clair, si vous exécutez UploadQueue.DoNext() plusieurs fois dans une courte période de temps, il n'y aura aucun travailleur qui n'est pas occupé, et vous obtenez un travailleur nul