-1

我有这个棘手的任务,我一直试图安静地完成,但直到现在我想不出任何办法让它工作。无论如何,这是场景......

我有一个 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....
});

现在上面的代码完美运行......但有时我希望用户中止当前正在运行的某个线程并继续列表中的其余线程......这可以实现吗?如果是这样,请帮帮我..我真的很感激任何解决方案或建议..

4

2 回答 2

2

尝试使用带有取消令牌的任务库。我发现做你的事情更优雅、更安全。这是一个很好的例子:

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

于 2011-09-28T08:09:05.893 回答
-1

好的,在为此苦苦挣扎之后,我终于找到了一个有效且简单的解决方案..

它只需要一个哈希表,其中包含列表视图中所选项目的索引和一个简单的布尔值。index 是键,bool (true, false) 是值。bool 值就像一个(开/关)开关,指示当前循环是否中止。所以为了简单地中止特定线程,我需要将列表视图上所选项目的键(索引)传递给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
}
});

就是这样。。

于 2011-09-27T11:55:18.650 回答