Нужна помощь в отладке, почему свойство не установлено / ноль - PullRequest
1 голос
/ 28 ноября 2010

У меня есть класс WorkQueue, просто обратите внимание на DoNext(), остальные - в основном помощники. По сути, WorkQueue - это просто очередь WorkItems. DoNext() отвечает за «Запуск ожидающего рабочего элемента с бесплатным фоновым рабочим». Также обратите внимание, что он установит свойство WorkItem.Worker.

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();
    }
}

Проблема, с которой я сталкиваюсь, это когда я делаю что-то вроде ниже,

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

Где UploadQueue является WorkQueue<string, UploadedImage>. На 1-м (только первом) DoNext() значение WorkItem.Worker равно нулю. Я знаю это, потому что моя кнопка Отмена, связанная с WorkItem.CancelCommand, отключена. При отладке я обнаружил, что причина в том, что работник равен нулю.

_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;
});

Решение состоит в том, чтобы вывести DoNext() из цикла,

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

но в чем проблема с этим внутри, почему рабочий установлен на ноль? Если его значение равно null, из условия if не должно начинаться BackgroundWorker?

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

Видео, демонстрирующее проблему

1 Ответ

1 голос
/ 15 июня 2011
public BackgroundWorker GetWorker()
{
    return (from worker in _workers
            where worker.IsBusy == false
            select worker).FirstOrDefault();
}

если все рабочие заняты, эта функция вернет ноль;

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

UploadQueue.DoNext () выполняется несколько раз

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

UploadQueue.DoNext () выполняется один раз.

Тогда совершенно ясно, что если вы выполните UploadQueue.DoNext () несколько раз за короткий промежуток времени, не будет ни одного работника, который не занят, так что вы получите нулевого работника

...