如何在c#任务并行库中终止特定线程
本文关键字:终止 线程 并行 任务 | 更新日期: 2023-09-27 18:09:52
我有一项棘手的任务,我一直试图安静地完成一段时间,但直到现在我还想不出任何办法来完成它。无论如何,这是一个场景…
我有一个包含列表视图和按钮的winform应用程序。listview包含1列,其中包含我需要稍后传递给我的函数的数据。列包含50行,其中包含一个链接列表。
现在我有这个函数,我用它来获取和抓取这些链接的内容(5个链接一次)与并行多线程模式使用(任务并行库):
//List<int> currentWorkingItem //contains the indices of the items in listview
//List<string> URLsList //contains the URLs of the items in listview
Parallel.ForEach(URLsList, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, (url, i, j) =>
{
//show to user this link is currently being downloaded by highlighting the item to green...
this.BeginInvoke((Action)(delegate()
{
//current working item
mylistview.Items[currentWorkingItem[(int)j]].BackColor = green;
}));
//here I download the contents of every link in the list...
string HtmlResponse = GetPageResponse(url);
//do further processing....
});
现在上面的代码工作得很好…但有时我希望用户中止当前正在运行的某些线程,并继续使用列表中的其他线程…这是可以实现的吗?如果是的话,请帮助我。我非常感谢任何解决方案或建议。
尝试使用带有取消令牌的任务库。我觉得这样做更优雅更安全。下面是一个很好的例子:
using System;
using System.Threading.Tasks;
using System.Threading;
namespace CancelTask
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press 1 to cancel task");
var cTokenSource = new CancellationTokenSource();
// Create a cancellation token from CancellationTokenSource
var cToken = cTokenSource.Token;
// Create a task and pass the cancellation token
var t1 = Task<int>.Factory.StartNew(()
=> GenerateNumbers(cToken), cToken);
// to register a delegate for a callback when a
// cancellation request is made
cToken.Register(() => cancelNotification());
// If user presses 1, request cancellation.
if (Console.ReadKey().KeyChar == '1')
{
// cancelling task
cTokenSource.Cancel();
}
Console.ReadLine();
}
static int GenerateNumbers(CancellationToken ct)
{
int i;
for (i = 0; i < 10; i++)
{
Console.WriteLine("Method1 - Number: {0}", i);
Thread.Sleep(1000);
// poll the IsCancellationRequested property
// to check if cancellation was requested
if (ct.IsCancellationRequested)
{
break;
}
}
return i;
}
// Notify when task is cancelled
static void cancelNotification()
{
Console.WriteLine("Cancellation request made!!");
}
}
}
原文可在此找到:http://www.dotnetcurry.com/ShowArticle.aspx?ID=493
好了,经过一番努力,我终于找到了一个有效而简单的解决方案。
它只需要一个哈希表,其中包含列表视图中所选项目的索引和一个简单的bool值。索引是键,bool (true, false)是值。bool值就像一个(on/off)开关,表示当前循环是否中止。因此,为了中止特定的线程简单,我需要将我的listview中选定项目的键(索引)传递给foreach循环,并检查bool开关是否打开或关闭,这基本上就是它…
所以我的最终代码是这样的://I declared the hashtable outside the function so I can manage it from different source.
private Hashtable abortingItem;
现在,当我点击抓取按钮,它应该填充哈希表与选定的索引…
abortingItem = new Hashtable();
for (int i = 0; i < myURLslist.SelectedItems.Count(); i++)
{
//false means don't abort this.. let it run
abortingItem.Add(myURLslist.SelectedItems[i].index, false);
}
//here should be the code of my thread to run the process of grabbing the URLs (the foreach loop)
//..........................
现在,如果我需要中止特定的项目,我所需要做的就是在列表视图中选择项目,然后点击中止按钮
private void abort_Click(object sender, EventArgs e)
{
if (abortingItem != null)
{
for (int u = 0; u < myURLslist.SelectedIndices.Count; u++)
{
//true means abort this item
abortingItem[myURLslist.SelectedIndices[u]] = true;
}
}
}
在我的foreach循环中,我所需要的只是一个简单的if else语句来检查bool是打开还是关闭:
//List<int> currentWorkingItem //contains the indices of the items in listview
//List<string> URLsList //contains the URLs of the items in listview
Parallel.ForEach(URLsList, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, (url, i, j) =>
{
//aborting
if (!(bool)abortingItem[currentWorkingItem[(int)j]])
{
//show to user this link is currently being downloaded by highlighting the item to green...
this.BeginInvoke((Action)(delegate()
{
//current working item
mylistview.Items[currentWorkingItem[(int)j]].BackColor = green;
}));
//here I download the contents of every link in the list...
string HtmlResponse = GetPageResponse(url);
//do further processing....
}
else
{
//aborted
}
});