我有一个带有三个按钮的Windows窗体。一个按钮将条目添加到BlockingCollection。一个开始处理列表,一个停止处理列表。
我可以将条目添加到我的BlockingCollection中,当我单击"开始"时,列表会按我的预期消耗掉。我仍然可以添加新的项目,它们将继续被消费。但是,当我单击"停止"按钮时,尽管任务确实停止了,但我无法使用"开始"按钮再次启动它们。
我在取消任务的过程中做错了什么,他们不会重新开始?我读过无数关于取消任务的文章,但仍然没有"明白"。
任何帮助都会很棒。这是代码。。。
// Blocking list for thread safe queuing
private BlockingCollection<QueueItem> ItemList = new BlockingCollection<QueueItem>();
private CancellationTokenSource CancelTokenSource = new CancellationTokenSource();
private int MaxConsumers = 3;
// Form initialisation
public MainForm()
{
InitializeComponent();
}
// Create an async consumer and add to managed list
private void CreateConsumer(int iIdentifier)
{
Task consumer = Task.Factory.StartNew(() =>
{
foreach (QueueItem item in ItemList.GetConsumingEnumerable())
{
Console.WriteLine("Consumer " + iIdentifier.ToString() + ": PROCESSED " + item.DataName);
Thread.Sleep(894);
if (CancelTokenSource.IsCancellationRequested)
break; // Cancel request
}
}, CancelTokenSource.Token);
}
// Add a new item to the queue
private void buttonAdd_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() =>
{
// Add an item
QueueItem newItem = new QueueItem(RandomString(12));
// Add to blocking queue
ItemList.Add(newItem);
});
}
}
// Start button clicked
private void buttonStart_Click(object sender, EventArgs e)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
// Create consumers
for (int i = 0; i < MaxConsumers; i++)
{
CreateConsumer(i);
}
}
// Stop button clicked
private void buttonStop_Click(object sender, EventArgs e)
{
CancelTokenSource.Cancel();
buttonStop.Enabled = false;
buttonStart.Enabled = true;
}
// Generate random number
private static Random random = new Random((int)DateTime.Now.Ticks);
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString();
}
您重复使用仍然配置为取消的相同取消令牌。
因此,在启动新任务时创建一个新的令牌。
不要在类本身中实例化CancellationTokenSource
。当您调用CancellationTokenSource.Cancel()
时,任务将被取消,因此当您再次尝试重新启动任务时,它将不会启动,因为它被CancellationTokenSource
的CancellationToken
取消,并且它的范围在整个类中。
请参阅此处:
Task consumer = Task.Factory.StartNew(YourTaskObject, cancellationTokenSource.Token);
// Similarly for Task.Run()
Task consumer = Task.Run(YourTaskObject, cancellationTokenSource.Token);
因此,将您的代码修改为:
// Instantiate it as null in the beginning
CancellationTokenSource cancellationTokenSource;
private void CreateConsumer(int iIdentifier) // Your method
{
if (cancellationTokenSource == null || cancellationTokenSource.IsCancellationRequested)
{
// This is the simplest form to initialize as a new object initially or after cancelling task everytime
cancellationTokenSource = new CancellationTokenSource();
}
... // Rest of the code
}
这也适用于Task.Run()。