Я пытался сделать должную осмотрительность, прежде чем задавать этот вопрос, но я не могу найти то, что я ищу. Я считаю, что столкнулся с проблемой производитель-потребитель . Я пишу приложение winforms в C #, которое использует два потока: один для пользовательского интерфейса и один для фонового работника. Элементы добавляются в очередь задач через обработчик событий кнопки отправки (т. Е. Всякий раз, когда пользователь нажимает кнопку «Отправить»). Если в очереди уже ничего нет, то вызывается фоновый работник и начинает обрабатывать очередь. Если фоновый работник занят, то задача просто добавляется в очередь. Теоретически, фоновый работник перейдет к следующему элементу в очереди, когда закончит свою текущую работу.
В моем потоке пользовательского интерфейса у меня есть следующий код, который создает экземпляр объекта DiscQueue, а затем добавляет элементы в его очередь:
private DiscQueue discQueue = new DiscQueue();
this.discQueue.AddToQueue(currentCD);
Ниже мой класс DiscQueue. Моя функция AddToQueue добавляет диск в очередь и затем вызывает RunWorkerAsync (), если bw еще не занят. Затем в bw_DoWork я извлекаю элемент из очереди и выполняю над ним ту работу, которую мне нужно сделать. Когда bw завершает свою задачу, он должен вызвать bw_RunWorkerCompleted, который должен направить его на продолжение работы через очередь, если в очереди есть больше элементов.
class DiscQueue
{
private Queue<Disc> myDiscQueue = new Queue<Disc>();
private BackgroundWorker bw = new BackgroundWorker();
// Initializer
public DiscQueue()
{
// Get the background worker setup.
this.bw.WorkerReportsProgress = false;
this.bw.WorkerSupportsCancellation = false;
this.bw.DoWork += new DoWorkEventHandler(bw_DoWork);
}
public void AddToQueue(Disc newDisc)
{
this.myDiscQueue.Enqueue(newDisc);
if (!this.bw.IsBusy)
{
this.bw.RunWorkerAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
DiscPreparationFactory discToPrepare = new DiscPreparationFactory();
Disc currentDisc = new Disc();
currentDisc = this.myDiscQueue.Dequeue();
discToPrepare.PrepareAndPublish(currentDisc);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.myDiscQueue.Count > 0)
{
this.bw.RunWorkerAsync();
}
}
}
В ходе тестирования я обнаружил, что быстрое последовательное добавление элементов в очередь каким-то образом забивает очередь, так что всем элементам в очереди присваивается значение (возможно, ссылка на?) Последнего элемента, добавленного в очередь. Когда я проходил по коду в отладке, похоже, что это происходит к тому времени, когда вы переходите к if (! This.bw.IsBusy) в функции AddToQueue. Я не уверен, что происходит.
Помимо ответа на мой конкретный вопрос, я уверен, что я делаю басы, и я был бы очень рад узнать "правильный способ" сделать это.
РЕДАКТИРОВАТЬ: Вот мой класс диска:
public class Disc
{
public enum DiscFormat
{
Audio,
Data,
}
private string sku;
private int quantity;
private DiscFormat format;
public string Sku
{
get
{
return this.sku;
}
set
{
this.sku = value;
}
}
public DiscFormat Format
{
get
{
return this.format;
}
set
{
this.format = value;
}
}
public int Quantity
{
get
{
return this.quantity;
}
set
{
this.quantity = value;
}
}
}
РЕДАКТИРОВАТЬ 2: Мой объект DiscQueue создается в моем файле MainForm.cs следующим образом:
public partial class MainForm : Form
{
Disc currentCD = new Disc();
private DiscQueue discQueue = new DiscQueue();
public MainForm()
{
// Do some stuff...
}
// Skipping over a bunch of other methods...
private void buttonSubmit_Click(object sender, EventArgs e)
{
currentCD.Sku = this.textBoxSku.Text;
currentCD.Quantity = (int)this.numericUpDownQuantity.Value;
if (this.radioButtonAudio.Checked)
currentCD.Format = Disc.DiscFormat.Audio;
else
currentCD.Format = Disc.DiscFormat.Data;
this.discQueue.AddToQueue(currentCD);
}
}