Task启动,暂停,继续,结束

时间:2025-03-26 07:46:45

延时:

async Task DelayMethod()
{
    ("Before Delay");
    await (1000); // 延时1秒
    ("After Delay");
}

构造方法: 

在C#中,可以使用Task类来创建和管理多线程任务。以下是Task的启动、暂停、继续和结束的方法:

启动Task:
1. 使用()方法启动一个新的Task。
2. 使用()方法启动一个新的Task。
3. 使用Task构造函数创建一个新的Task,然后调用()方法启动它。

暂停Task:
1. 使用ManualResetEvent类创建一个事件对象,然后在Task中使用WaitOne()方法暂停Task。
2. 使用CancellationTokenSource类创建一个取消令牌对象,然后在Task中使用该对象的Cancel()方法暂停Task。

继续Task:
1. 使用ManualResetEvent类的Set()方法继续Task。
2. 使用CancellationTokenSource类的Cancel()方法取消暂停Task。

结束Task:
1. 使用()方法等待Task完成。
2. 使用()方法等待多个Task完成。
3. 使用()方法等待任何一个Task完成。
4. 使用Task的CancellationTokenSource对象的Cancel()方法取消Task。

public Task(Action action);
public Task(Action action, CancellationToken 取消令牌);
public Task(Action action, TaskCreationOptions 创建选项);
public Task(Action<object> action, object 状态);
public Task(Action action, CancellationToken 取消令牌, TaskCreationOptions 创建选项);
public Task(Action<object> action, object 状态, CancellationToken 取消令牌);
public Task(Action<object> action, object 状态, TaskCreationOptions 创建选项);
public Task(Action<object> action, object 状态, CancellationToken 取消令牌, TaskCreationOptions 创建选项);

public static Task Run(Func<Task> function, CancellationToken cancellationToken关闭线程)
// ctrl+F查找,3312行

第二参数:用于关闭线程。(字段位置)

//CancellationToken   ct = new CancellationToken();
private CancellationTokenSource cts ;//关闭线程用(包含ct)
private ManualResetEvent resetEvent = new ManualResetEvent(true);// 暂停业务

 public static async Task Main()
   {
      var tokenSource = new CancellationTokenSource();// 令牌对象
      var token = ;// 开关绑定
      var files = new List<Tuple<string, string, long, DateTime>>();

      var t = ( () => { string dir = "C:\\Windows\\System32\\";
                                object obj = new Object();
                                if ((dir)) {
                                   ((dir),
                                   f => {
                                           if ()
                                              ();
                                           var fi = new FileInfo(f);
                                           lock(obj) {
                                              ((, , , ));          
                                           }
                                      });
                                 }
                              }
                        , token);// 开关绑定
      await ();
      ();// 令牌对象

【1】新建线程

cts = new CancellationTokenSource();//关闭线程用
Task task1 = new Task(() =>
            {
                //在这个地方编写我们需要的逻辑...
            }, );
();// 这句才开启


 (() => {
                              canopen.set_reg32bit(Convert.ToInt16(, 16), 0, Convert.ToInt32(, 16));
                             });
 (() =>
            {
                //这里填业务。。。。。
               i= canopen.get_region(Convert.ToInt16(, 16), (, 16));

                (new Action(() =>
                {
                    //这里填窗体业务。。。。。

                     = ("X8");
                }));
            }
            );


(() =>
            {
                canopen.set_reg32bit(0x1017, 0x00, 7000);

            }   );
Task<int> task = (() =>
{
    // 这里是需要执行的代码
    return 42;
});

// 这里可以执行一些其他的代码

int result = ; // 这里会阻塞当前线程,直到任务完成并返回结果
(result); // 输出 42

//启动线程
        private void btnStart_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();// 令牌
            CancellationToken ct = ; //获取令牌

            Task task = new Task(async () =>
            {
                while (true)
                {
                    if (!)
                    {
                        ();

                        //在下面编写你要让线程完成的任务...
                        ("任务执行中...");
                        await (1000);
                    }
                    else
                    {
                        return;// 结束线程
                    }
                }
            }, ct);
            ();

            //();// 结束线程
        }
//暂停   ();
//继续   ();
//结束   ();

令牌结束,没有作用,实际还是要方法体内判断状态,如果是结束,退出方法体,线程才真正结束。 ();只是将只读属性True,方法体内return才真正结束线程。

 Task task3 = (() =>
            {
                //在这个地方编写我们需要的逻辑...
            });

【2】排队等待:

     Task task1 = new Task(() =>
             {
                 (1000);
                 ($"Task1子线程Id={}  {()}");
             });
            ();
            Task task2 = new Task(() =>
            {
                (2000);
                ($"Task2子线程Id={}  {()}");
            });
            ();

            //第1种方式:挨个等待和前面一样
            //();
            //();

            //第2种方式:等待所有的任务完成    【推荐】
            //(task1, task2);

            //第3种方式:等待任何一个完成即可  【推荐】
            (task1, task2);

            ("主线程开始运行!Time=" + ());
//线程的延续(主线程不等待,子线程依次执行,如果你需要主线程也按照子线程的顺序来,请你自己把主线程的任务放到延续任务中就可以)
            (task1, task2).ContinueWith(task3 =>
             {
                 //在这里可以编写你需要的业务...

                 ($"Task3子线程Id={}  {()}");
             });

            ("主线程开始运行!Time=" + ());

12都完成3才run

//线程的延续(主线程不等待,子线程任何一个执行完毕,就会执行后面的线程)
            (task1, task2).ContinueWith(task3 =>
            {
                //在这里可以编写你需要的业务...

                ($"Task3子线程Id={}  {()}");
            });

有1个完成,3就run 

Task parentTask = new Task(() =>
             {
                 Task task1 = new Task(() =>
                  {
                      (1000);
                  }, );

                 Task task2 = new Task(() =>
                 {
                     (3000);
                 }, );
                 ();
                 ();
             });

            ();
            ();//等待附加的子任务全部完成。相当于(taks1,task2);
            //如果这个枚举参数不添加,主线程会直接运行,不等待
            ("主线程开始执行!Time=  " + ());

耗时线程: 

//长时间的任务运行,需要采取的方法
            Task task1 = new Task(() =>
            {
                (2000);
               
            }, );

            //LongRunning:如果你明确知道这个任务是长时间运行的,建议你加上。当然你使用Thread也是可以的。但是不要使用
            //ThreadPool,因为长时间占用不归还线程,系统会强制开启新的线程,会一定程度影响性能
            ();
            ();

            ("主线程开始执行!Time=  " + ());
        

【3】线程取消

using System;
using ;
using ;

class Program
{
    static async Task Main()
    {
        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = ;

        var task = (() =>
        {
            // Were we already canceled?
            ();

            bool moreToDo = true;
            while (moreToDo)
            {
                // Poll on this property if you have to do
                // other cleanup before throwing.
                if ()
                {
                    // Clean up here, then...
                    ();
                }
            }
        }, ); // Pass same token to .

        ();

        // Just continue on this thread, or await with try-catch:
        try
        {
            await task;
        }
        catch (OperationCanceledException e)
        {
            ($"{nameof(OperationCanceledException)} thrown with message: {}");
        }
        finally
        {
            ();
        }

        ();
    }
}

// /zh-cn/dotnet/standard/parallel-programming/task-cancellation

 任务取消 | Microsoft Learn

//创建取消信号源对象
            CancellationTokenSource cts = new CancellationTokenSource();

            Task task = (() =>
              {
                  while (!)//判断任务是否被取消
                  {
                      (200);

                      ($"子线程Id={}  {()}");
                  }
              }, );

            //我们在这个地方模拟一个事件产生
            (2000);
            ();//取消任务,只要传递这样一个信号就可以
 CancellationTokenSource cts = new CancellationTokenSource();
            Task task = (() =>
            {
                while (!)
                {
                    (500);

                    ($"子线程Id={}  {()}");
                }
            }, );

            //注册一个委托:这个委托将在任务取消的时候调用
            (() =>
            {
                //在这个地方可以编写自己要处理的逻辑...
                ("任务取消,开始清理工作......");
                (2000);
                ("任务取消,清理工作结束......");
            });

            //这个地方肯定是有其他的逻辑来控制取消
            (3000);//模拟其他的耗时工作
            ();//取消任务

限时任务: 

(3000); //3秒后自动取消

重新开的线程,需要用新的cts绑定。

Lock锁:锁对象,必须是引用类型

 //为什么要用锁?在多线程中,尤其是静态资源的访问,必然会有竞争

        private static int nums = 0;
        private static object myLock = new object();// 必须引用类型
        static void Method12()
        {
            for (int i = 0; i < 5; i++)
            {
                (() =>
                {
                    TestMethod();
                });
            }
        }

        static void TestMethod()
        {
            for (int i = 0; i < 100; i++)
            {
                lock (myLock)// 锁住引用类型
                {
                    nums++;
                    (nums);
                }
            }
        }
        //Lock是Monitor语法糖,本质是解决资源的锁定问题
        //我们锁住的资源一定是让线程可访问到的,所以不能是局部变量。
        //锁住的资源千万不要是值类型。
        //lock也不能锁住string类型。

lock内,对象是同一个,才能进入

using System;
using ;
using ;
using ;

public class Example
{
   public static void Main()
   {
      // Define the cancellation token.
      CancellationTokenSource source = new CancellationTokenSource();
      CancellationToken token = ;

      Random rnd = new Random();
      Object lockObj = new Object();
      
      List<Task<int[]>> tasks = new List<Task<int[]>>();
      TaskFactory factory = new TaskFactory(token);
      for (int taskCtr = 0; taskCtr <= 10; taskCtr++) {
         int iteration = taskCtr + 1;
         (( () => {
           int value;
           int[] values = new int[10];
           for (int ctr = 1; ctr <= 10; ctr++) {
              lock (lockObj) {
                 value = (0,101);
              }
              if (value == 0) { 
                 ();
                 ("Cancelling at task {0}", iteration);
                 break;
              }   
              values[ctr-1] = value; 
           }
           return values;
        }, token));   
      }
      try {
         Task<double> fTask = ((), 
         (results) => {
            ("Calculating overall mean...");
            long sum = 0;
            int n = 0; 
            foreach (var t in results) {
               foreach (var r in ) {
                  sum += r;
                  n++;
               }
            }
            return sum/(double) n;
         } , token);
         ("The mean is {0}.", );
      }   
      catch (AggregateException ae) {
         foreach (Exception e in ) {
            if (e is TaskCanceledException)
               ("Unable to compute mean: {0}", 
                  ((TaskCanceledException) e).Message);
            else
               ("Exception: " + ().Name);
         }
      }
      finally {
         ();
      }
   }
}
// Repeated execution of the example produces output like the following:
//       Cancelling at task 5
//       Unable to compute mean: A task was canceled.
//       
//       Cancelling at task 10
//       Unable to compute mean: A task was canceled.
//       
//       Calculating overall mean...
//       The mean is 5.29545454545455.
//       
//       Cancelling at task 4
//       Unable to compute mean: A task was canceled.
//       
//       Cancelling at task 5
//       Unable to compute mean: A task was canceled.
//       
//       Cancelling at task 6
//       Unable to compute mean: A task was canceled.
//       
//       Calculating overall mean...
//       The mean is 4.97363636363636.
//       
//       Cancelling at task 4
//       Unable to compute mean: A task was canceled.
//       
//       Cancelling at task 5
//       Unable to compute mean: A task was canceled.
//       
//       Cancelling at task 4
//       Unable to compute mean: A task was canceled.
//       
//       Calculating overall mean...
//       The mean is 4.86545454545455.