我的要求是在队列中插入项目并对其进行处理,但应首先添加项目,并在一段时间后处理它们(因为在处理项目之前需要设置其他一些内容)这是我到目前为止所做的编码。
#region Variables Declarations
private Thread threadTask = null;
ConcurrentQueue<string> concurrentQueue = new ConcurrentQueue<string>();
string currentSeqNo;
string previousSeqNo = "-1";
#endregion
private void test1_Load(object sender, EventArgs e)
{
AddItems();
if (threadTask == null)
{
threadTask = new Thread(Kick);
Thread.Sleep(5000);
threadTask.Start();
}
}
private void AddItems()
{
for (Int64 i = 100000; i < 300000; i++)
{
concurrentQueue.Enqueue(i.ToString());
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = i.ToString();
label1.Update();
}));
}
}
private void Kick()
{
while (true)
{
int recordCountNew = concurrentQueue.Count();
if (recordCountNew != 0)
{
RemoveItems();
}
}
}
private void RemoveItems()
{
string item;
while (concurrentQueue.TryDequeue(out item))
{
this.Invoke(new MethodInvoker(delegate()
{
label2.Text = item;
label2.Update();
}));
currentSeqNo = item; // second time does not start wil 100000
if (previousSeqNo != "-1")
{
if (long.Parse(currentSeqNo) != long.Parse(previousSeqNo) + 1)
{
Reconnect();
}
else
{
//Process item
previousSeqNo = currentSeqNo;
}
}
else
{
//Process item
previousSeqNo = currentSeqNo;
}
}
}
private void Reconnect()
{
currentSeqNo = "";
previousSeqNo = "-1";
string someItem;
while (concurrentQueue.Count > 0)
{
concurrentQueue.TryDequeue(out someItem);
}
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = "";
label2.Text = "";
label1.Update();
label2.Update();
}));
AddItems();
if (threadTask == null)
{
threadTask = new Thread(Kick);
threadTask.Start();
}
}
private void button1_Click_1(object sender, EventArgs e)
{
Reconnect();
}
要重现此问题:运行应用程序并在中间单击按钮。现在队列应该再次从100000开始,但它显示的数字大于100000.
请告知我如何在点击按钮后释放所有资源以重新启动。虽然我将它们设置为默认值并清除队列但是当&#39; RemoveItems&#39;时,它仍会在currentSeqNo中显示旧值。方法被调用。
答案 0 :(得分:0)
几点意见:
1)你Kick()
方法有一个无限循环,也没有睡眠。每个启动的线程都会继续运行,因为你没有线程的范围。
您可以拥有bKeepRunning
之类的成员变量,默认值为true
。在false
函数的开头将该变量设置为Reconnect()
。类似的东西:
private void Kick()
{
while (bKeepRunning)
{
int recordCountNew = concurrentQueue.Count();
if (recordCountNew != 0)
{
RemoveItems();
}
}
}
Thread.Sleep(5000);
中有test1_Load()
?我不认为这是必要的。 我对您的代码做了一些小改动,例如:
private void AddItems()
{
for (Int64 i = 100000; i < 300000; i++)
{
concurrentQueue.Enqueue(i.ToString());
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = i.ToString();
label1.Update();
}));
if (i < 100004)
Thread.Sleep(1000);
}
}
private void Kick()
{
while (bKeepRunning)
{
int recordCountNew = concurrentQueue.Count();
if (recordCountNew != 0)
{
RemoveItems();
}
}
}
private void Reconnect()
{
currentSeqNo = "";
previousSeqNo = "-1";
bKeepRunning = false;
threadTask = null;
string someItem;
while (concurrentQueue.Count > 0)
{
concurrentQueue.TryDequeue(out someItem);
}
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = "";
label2.Text = "";
label1.Update();
label2.Update();
}));
Thread.Sleep(2000);
AddItems();
bKeepRunning = true;
if (threadTask == null)
{
threadTask = new Thread(Kick);
threadTask.Start();
}
}
它帮助我看到价值从100000开始。您可以尝试相同的结果。
注意:我已停止线程并在单击按钮后重新启动。因此,我不会在您的代码中看到任何缺陷。它只是快速运行,因此您无法实现起始值。
答案 1 :(得分:0)
你看到的是Kick线程和按钮点击处理程序之间的竞争条件。当您按下按钮时,在其中执行Reconnect(),您清理队列,然后调用AddItems()函数。但是所有这一次Kick函数都会尝试Dequeue,因此每次都会有一个任意数量的项目。您应该做的是在这些功能之间进行同步,或者在添加项目时阻止Kick执行。
答案 2 :(得分:0)
您应该使 UI线程和 threadTask线程同步,只需使用 ManualResetEventSlim 信号构造,就像这样:
static ManualResetEventSlim guard = new ManualResetEventSlim(true);
private void button1_Click_1(object sender, EventArgs e)
{
guard.Reset();
Reconnect();
guard.Set();
}
private void RemoveItems()
{
string item;
while (concurrentQueue.TryDequeue(out item))
{
guard.Wait();
//......
}
}
请参阅: