C# 为什么我的任务队列中的所有项目都被分配了相同的值?
在问这个问题之前,我一直在做尽职调查,但我似乎找不到我要找的东西。我相信我会遇到你。我正在用C编写一个winforms应用程序,它使用两个线程:一个用于UI,一个用于后台工作程序。项目通过submit按钮事件处理程序添加到任务队列中(即,每当用户点击“submit”时)。如果队列中已经没有任何内容,则调用后台工作程序并开始处理队列。如果后台工作人员正忙,则只需将任务添加到队列中即可。理论上,后台工作人员在完成当前工作后将转到队列中的下一项 在我的UI线程中,我有以下代码实例化DiscQueue对象,然后将项目添加到其队列中:C# 为什么我的任务队列中的所有项目都被分配了相同的值?,c#,winforms,multithreading,backgroundworker,task-queue,C#,Winforms,Multithreading,Backgroundworker,Task Queue,在问这个问题之前,我一直在做尽职调查,但我似乎找不到我要找的东西。我相信我会遇到你。我正在用C编写一个winforms应用程序,它使用两个线程:一个用于UI,一个用于后台工作程序。项目通过submit按钮事件处理程序添加到任务队列中(即,每当用户点击“submit”时)。如果队列中已经没有任何内容,则调用后台工作程序并开始处理队列。如果后台工作人员正忙,则只需将任务添加到队列中即可。理论上,后台工作人员在完成当前工作后将转到队列中的下一项 在我的UI线程中,我有以下代码实例化DiscQueue对
private DiscQueue discQueue = new DiscQueue();
this.discQueue.AddToQueue(currentCD);
下面是我的DiscQueue课程。My AddToQueue函数将光盘添加到队列中,然后在bw还不忙的情况下调用RunWorkerAsync()。然后,在bw_DoWork中,我从队列中获取一个项目,并对其执行我需要执行的工作。当bw完成任务时,它应该调用bw_RunWorkerCompleted,如果队列中有更多的项目,它应该指示bw继续在队列中工作
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();
}
}
}
编辑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);
}
}
标准的.Net不是“线程安全的”;重点地雷:
只要不修改集合,队列
可以同时支持多个读卡器。即便如此,通过集合枚举本质上并不是线程安全的过程。为了保证枚举期间的线程安全,可以在整个枚举期间锁定集合要允许多个线程访问集合进行读写,您必须实现自己的同步。
如果你有.NET4.0,你应该考虑改用.NET4.0
如果没有,您可以使用一个简单的锁来保护DiscQueue
中的读/写访问:
/// <summary>
/// Synchronizes access to <see cref="DiscQueue.myDiscQueue" />.
/// </summary>
private object queueLock = new object();
currentDisk是如何声明/初始化的?请发布更多实例化DiskQueue对象的代码。您提供的代码不完整。@Ramhound-是。。。我不认为这是个问题。我的程序中只有一个DiscQueue。@idweeks-忽略该注释的第一个版本。currentCD似乎是在窗体类的顶部定义的。除此之外,在哪里创建新实例?换句话说,您还可以在哪里执行currentCD=new Disc()?如果没有,那么你只是在更新同一个对象并对其重新排队。我一直在玩弄各种锁定策略,我不太确定如何使它工作。问题是UI线程正在排队,而工作线程正在解排队。我的理解已经更新,以显示读者和作者之间的关系。
/// <summary>
/// Synchronizes access to <see cref="DiscQueue.myDiscQueue" />.
/// </summary>
private object queueLock = new object();
Disc currentDisc = null;
lock (this.queueLock)
{
// protect instance members of Queue<T>
if (this.myDiscQueue.Count > 0)
{
currentDisc = this.myDiscQueue.Dequeue();
}
}
// work with currentDisk
lock (this.queueLock)
{
this.myDiscQueue.Add(currentCD);
}