-1

私はいつか静かに達成しようとしてきたこのトリッキーなタスクを持っていますが、今までそれを機能させるために何も考えられませんでした. とにかくここにシナリオがあります...

リストビューとボタンを含むwinformアプリケーションがあります。リストビューには、後で関数に渡す必要があるデータを保持する 1 つの列が含まれています。列には、リンクのリストを含む 50 行としましょう。

これで、(Task Parallel Library) を使用して並列マルチスレッド モードでこれらのリンク (一度に 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

これに苦労した後、私はついにこれに対する効率的で簡単な解決策を見つけました。

リストビューで選択したアイテムのインデックスと単純なブール値を含むハッシュテーブルのみが必要でした。インデックスがキーで、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ループで必要なのは、ブール値がオンかオフかを確認するための単純なifelseステートメントだけです。

//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 に答える