是否可以为List <task>中的任务设置超时并仅取消长期运行的任务?

时间:2015-05-12 14:09:43

标签: c# asynchronous task-parallel-library .net-4.5

我是c#的新手(也是英语),我尝试在后台并行做一些工作。我有一个包含“MyClass”对象的列表。每个都有一个“DoWork()”函数,我把这个函数放在一个列表然后我将运行所有。我有两个问题:1,这都错了吗? 2,当第一个回答是“否”时,那么是否可以设置函数的最大运行时间(当“DoWork()”花费超过600毫秒时,我想要停止它,但其他人没有。)?抱歉我的英文不好!

这是我的代码:

public class MyClass
{
        static int nextId;
        public int id;
        public int x;
        public MyClass()
        {
            id = Interlocked.Increment(ref nextId);
            x = (id % 4 + 1) * 250; 
        }
        public void DoWork()
        {
            Console.Write("start: {0}", this.id);
            Thread.Sleep(x);  //this  simulate  the  work
            Console.WriteLine("end:  {0}", this.id);
        }
}

在main中:

for (int i = 0; i < db; i++)
{
    xy_list.Add(new MyClass());
}

List<Task> tasks3 = new List<Task>();
foreach (var item in xy_list)
{
   Task work = new Task(() => item.DoWork());                
   tasks3.Add(work);    
}
Parallel.ForEach(tasks3, task => 
{ 
      task.Start(); 
});  

1 个答案:

答案 0 :(得分:2)

你需要自己做一些工作。取消任务是一个合作过程(有关更多信息,请参阅Cancellation in Managed Threads)。

为了能够取消后台任务并让它们超时,您需要创建一个超时的CancellationTokenSource。此令牌源可用于为您正在启动的任务提供取消令牌,您还需要将它们传递给DoWork方法,该方法应检查是否请求取消。

如果您构建了具有超时的取消令牌源,它将在超时到期时发出所有已连接的取消令牌的信号。

在你的代码示例中使用它会使它看起来像这样:

public class MyClass
{
    static int nextId;
    public int id;
    public int x;
    public MyClass()
    {
        id = Interlocked.Increment(ref nextId);
        x = (id % 4 + 1) * 250; 
    }
    public void DoWork(CancellationToken cancelToken)
    {
        bool is_canceled = false;
        while (!cancelToken.IsCancellationRequested && cycle < 5)
        {
            try
            {
                Console.WriteLine("Task {0} waiting, tid = {1}", id, Thread.CurrentThread.ManagedThreadId);
                Task.Delay(x / 5, cancelToken).Wait(); // don't do Thread.Sleep()
                Console.WriteLine("Task {0} waking up, tid = {1}", id, Thread.CurrentThread.ManagedThreadId);
            }
            catch (AggregateException ex)
            {
                if (ex.InnerExceptions.Any(x => typeof(OperationCanceledException).IsAssignableFrom(x.GetType())))
                {
                    Console.WriteLine("Task {0} canceled, tid = {1}", id, Thread.CurrentThread.ManagedThreadId);
                    is_canceled = true;
                    break;
                }
                throw;
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Task {0} canceled, tid = {1}", id, Thread.CurrentThread.ManagedThreadId);
                is_canceled = true;
            }
            cycle++;
        }
        is_canceled |= cycle < 5;
        Console.WriteLine("{0} {1}, tid = {2}", this.id, is_canceled ? "canceled" : "completed", Thread.CurrentThread.ManagedThreadId);
    }
}

在你的&#34; main&#34;:

for (int i = 0; i < db; i++)
{
    xy_list.Add(new MyClass());
}

// set cancellation timeout for 600 ms.
var cancelSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(600));

// start all tasks
List<Task> tasks3 = new List<Task>();
foreach (var item in xy_list)
    tasks3.Add(Task.Run(() => item.DoWork(cancelSource.Token), cancelSource.Token));

// Wait for all tasks to be finished.
Task.WaitAll(tasks3.ToArray());