开发者

How to abort specific thread in task parallel library with C#

I have this tricky task I've been trying to achieve for quiet sometime but till now I couldn't think of anything to make it work. anyway here is the scenario...

I have a winform application contains a listview and a button. the listview contains 1 column which holds the data I need to pass to my functions later on. the column contains lets say 50 rows containing a list of links.

Now I have this function which I'm using to fetch and grab the contents of these links (5 links at a time) with parallel multithreaded mode using (Task Parallel Library):

//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) =>
{开发者_JAVA百科
    //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....
});

Now the above code works perfectly... but sometimes I want the user to abort certain thread which is currently running and continue with the rest of the threads in the list... is that achievable in this? if so please help me out.. I'd really appreciate any solution or suggestions..


Try using Task library with cancellation tokens. I find it more elegant and safer approach to do your thing. Here is a quote good example of doing that:

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

Original article could be found here: http://www.dotnetcurry.com/ShowArticle.aspx?ID=493


ok after struggling with this I finally found an efficient and an easy solution for this..

it required me only a hashtable which contains the indicies of the selected items in the listview and a simple bool value. the index is the key and the bool (true, false) is the value. the bool value is like an (on/off) switch indicates that the current loop is aborted or not.. so in order to abort specific thread simple I need to pass the key(the index) of the selected item on my listview to the foreach loop and check if the bool switch is on or off and that's basically it...

so my final code will be like this:

//I declared the hashtable outside the function so I can manage it from different source.

    private Hashtable abortingItem;

Now when I click grab button it should fill the hashtable with the selected indicies...

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)
//..........................

now if I need to abort specific item all I need is to select the item in the listview and click abort button

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

In my foreach loop all I need is a simple if else statement to check if the bool is on or off:

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

that's simply it..

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜