gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 22:33:01 25 4
gpt4 key购买 nike

在问这个问题之前,我一直在努力做尽职调查,但我似乎找不到我要找的东西。我相信我遇到了 producer-consumer problem .我正在用 C# 编写一个 winforms 应用程序,它使用两个线程:一个用于 UI,一个用于后台 worker 。项目通过提交按钮事件处理程序添加到任务队列(即,每当用户点击“提交”)。如果队列中已经没有任何内容,则会调用后台工作程序并开始处理队列。如果后台工作人员很忙,则只需将任务添加到队列中。理论上,后台工作人员在完成当前工作后将继续处理队列中的下一项。

在我的 UI 线程中,我有以下代码实例化一个 DiscQueue 对象,然后将项目添加到它的队列中:

private DiscQueue discQueue = new DiscQueue();
this.discQueue.AddToQueue(currentCD);

下面是我的 DiscQueue 类。我的 AddToQueue 函数将光盘添加到队列中,然后在 bw 尚未忙碌时调用 RunWorkerAsync()。然后,在 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();
}
}
}

在测试中,我发现快速连续地向队列中添加项目会以某种方式破坏队列,从而使队列中的所有项目都被赋予(可能是对?)最后添加到队列中的项目的值。当我逐步调试代码时,这似乎发生在您到达 AddToQueue 函数中的 if (!this.bw.IsBusy) 时。我不确定发生了什么。

除了回答我的具体问题外,我确信我做的事情都是低频的,我很高兴知道“正确的方法”来做到这一点。

编辑:这是我的光盘类:

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

最佳答案

标准.Net Queue<T> 不是“线程安全的”;强调我的:

A Queue<T> can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure. To guarantee thread safety during enumeration, you can lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

如果您有 .Net 4.0,您应该考虑使用 ConcurrentQueue<T> 相反。

如果没有,您可以保护 DiscQueue 内部的读/写访问权限用一把简单的锁:

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

关于c# - 为什么我的任务队列中的所有项目都分配了相同的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8508271/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com