C# 为什么我的任务队列中的所有项目都被分配了相同的值?

C# 为什么我的任务队列中的所有项目都被分配了相同的值?,c#,winforms,multithreading,backgroundworker,task-queue,C#,Winforms,Multithreading,Backgroundworker,Task Queue,在问这个问题之前,我一直在做尽职调查,但我似乎找不到我要找的东西。我相信我会遇到你。我正在用C编写一个winforms应用程序,它使用两个线程:一个用于UI,一个用于后台工作程序。项目通过submit按钮事件处理程序添加到任务队列中(即,每当用户点击“submit”时)。如果队列中已经没有任何内容,则调用后台工作程序并开始处理队列。如果后台工作人员正忙,则只需将任务添加到队列中即可。理论上,后台工作人员在完成当前工作后将转到队列中的下一项 在我的UI线程中,我有以下代码实例化DiscQueue对

在问这个问题之前,我一直在做尽职调查,但我似乎找不到我要找的东西。我相信我会遇到你。我正在用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);
}