C#中的多线程和取消令牌

本文关键字:取消 令牌 多线程 | 更新日期: 2023-09-27 18:12:21

我是多线程的新手,花了几天时间调试这个程序,但运气不佳。在进行生产之前,我正在尝试进行概念验证。

我有一个自定义对象的列表。它们的属性是Task类型的T和int类型的Timeout。为了演示的目的,我确实创建了两个简单的任务,他们做简单的事情

  public class Program
{
    public static void Main(string[] args)
    {
        CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
        CancellationToken cancellationToken = cancellationTokenSource.Token;
        List<MyItem> myItems = new List<MyItem>();
        myItems.Add(createtask1(2000,1000,cancellationToken)); // this task should run for one second....result: should timeout
        myItems.Add(createtask2(2000,3000,cancellationToken));// this task should run for two second....result: should NOT timeout
        Parallel.ForEach(myItems,(item)=>{
           Task task = item.T;
            // start the task
            task.Start();
            Console.WriteLine("waiting for the task with timeout:{0} to finish", item.Timeout);
            try{
                bool hasNotTimedOut = task.Wait(item.Timeout);
                if (hasNotTimedOut)
                {
                    Console.WriteLine("Task with timeout: {0}, has not timed out", item.Timeout);
                }
                else
                {
                    Console.WriteLine("Task with timeout: {0}, has timed out", item.Timeout);
                        cancellationTokenSource.Cancel();
                        Console.WriteLine("Status of the task with timeout: {0} is {1}", item.Timeout,task.Status.ToString());
                }
            }
            catch (AggregateException ex)
            {
                if (ex.InnerException is OperationCanceledException)
                {
                    Console.WriteLine("Status of the task with timeout: {0} is {1}5", item.Timeout,task.Status.ToString());
                }
                else
                    Console.WriteLine(ex);
            }

            });
        //    Task.WaitAll(myItems.Select(item=>item.T).ToArray());        
        Console.WriteLine("End of Main");
    }
    private static MyItem createtask1(int delayTime, int timeout,CancellationToken cancellationToken)
    {
        MyItem toReturn = new MyItem();
        toReturn.Timeout = timeout;
        toReturn.T = new Task(()=>{
                              Console.WriteLine("Task1 is getting executed with DelayTime:{0}, timeout:{1}",delayTime,timeout);
                              Task.Delay(delayTime).Wait();
                              Console.WriteLine("Task1 finished executing with DelayTime:{0}, timeout:{1}",delayTime,timeout);
            cancellationToken.ThrowIfCancellationRequested();
                              },cancellationToken);

        return toReturn;                     
    }
    private static MyItem createtask2(int delayTime, int timeout,CancellationToken cancellationToken)
    {
        MyItem toReturn = new MyItem();
        toReturn.Timeout = timeout;
        toReturn.T = new Task(()=>{
                              Console.WriteLine("Task2 is getting executed with DelayTime:{0}, timeout:{1}",delayTime,timeout);
                              Task.Delay(delayTime).Wait();
                              Console.WriteLine("Task2 finished executing with DelayTime:{0}, timeout:{1}",delayTime,timeout);
            cancellationToken.ThrowIfCancellationRequested();
                              },cancellationToken);
        return toReturn;                     
    }
}
public class MyItem{
    public Task T{get;set;}
    public int Timeout{get;set;}
}

它似乎试图取消最后一项任务,但在我的情况下,应该取消第一项任务。如果我不包括CancellationToken,我的代码会很好地工作,即它会告诉我什么任务超时。

你能告诉我我做错了什么吗

C#中的多线程和取消令牌

仅仅因为您将CancellationToken作为参数传递给Task,然后取消该Token,Task仍然不会被取消。您需要检查函数内部的Token,并在请求时手动取消Task。

CancellationToken可以传递给实现该系统的Task.Delay()

像这样:

private static MyItem createtask1(int delayTime, int timeout, CancellationToken cancellationToken)
    {
        MyItem toReturn = new MyItem();
        toReturn.Timeout = timeout;
        toReturn.T = new Task(() => {
            Console.WriteLine("Task1 is getting executed with DelayTime:{0}, timeout:{1}", delayTime, timeout);
            Task.Delay(delayTime, cancellationToken).Wait();
            Console.WriteLine("Task1 finished executing with DelayTime:{0}, timeout:{1}", delayTime, timeout);
            cancellationToken.ThrowIfCancellationRequested();
        }, cancellationToken);

        return toReturn;
    }

此外,您不需要cancellationToken.ThrowIfCancellationRequested();,因为等待Task.Delay()会在取消时引发异常。