您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

2026-03-31 08:381阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2228个文字,预计阅读时间需要9分钟。

您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

目录一. 启动任务

1.使用线程池的任务

2.同步任务

3.使用单线程的任务

二. 任务的结束结果三. 持续的任务四. 任务的层次结构五. Parallel类的并行任务

目录
  • 一.启动任务
    • 1.使用线程池的任务
    • 2.同步任务
    • 3.使用单独线程的任务
  • 二.任务的结果————Future
    • 三.连续的任务
      • 四.任务的层次结构

        Parallel类(www.jb51.net/article/244267.htm)的并行任务需要结束后才能运行后面的代码,如果想不等结束后在开始动作,可以使用Task类更好地控制并行动作。
        任务表示应完成的某个工作单元。这个工作单元可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主调线程。使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制。
        任务相对Parallel类提供了非常大的灵活性。例如,可以定义连续的工作——在一个任务完成后该执行什么工作。这可以根据任务成功与否来分。还可以在层次结构中安排任务。例如,父任务可以创建新的子任务。

        一.启动任务

        要启动任务,可以使用TaskFactory类或Task类的构造函数和Start()方法。Task类的构造函数在创建任务上灵活性比较大。
        在启动任务时,会创建Task类的一个实例,利用Action或Action<T>委托(不带参数或带一个参数),可以指定应运行的代码。

        1.使用线程池的任务

        线程池提供了一个后台线程的池(后面详细介绍了线程池)。线程池独自管理线程,根据需要增加或减少线程池中的线程数。线程池中的线程用于实现一些动作,之后仍然返回线程池中。
        下面介绍创建线程池的任务的四种方法:
        先定义一个要调用使用的方法:

          //避免写入控制台的操作交叉,这里使用lock关键字同步 static object taskMethodLock = new object(); static void TaskMethod(object title) { lock (taskMethodLock) { Console.WriteLine(title); Console.WriteLine("task id:{0},thread:{1}",Task.CurrentId,Thread.CurrentThread.ManagedThreadId); Console.WriteLine("is pooled thread:{0}",Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("is background thread:{0}",Thread.CurrentThread.IsBackground); } }

        (1).使用实例化的TaskFactory类,把TaskMethod方法和TaskMethod方法的参数传递给StartNew方法:

            var tf = new TaskFactory();     Task t1 = tf.StartNew(TaskMethod,"using a task factory");

        (2).使用Task类的静态属性Factory来访问TaskFactory,以调用StartNew()方法。类似第一种,也使用了工厂,但对工厂的控制没那么全面。

            Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task");

        (3).使用Task的构造函数。实例化Task对象时任务不会执行,只是指定Created状态。接着调用Start()方法,启动任务。

            Task t3 = new Task(TaskMethod,"using a task constructor and Start");     t3.Start();

        (4).直接调用Task类的Run()方法启动任务。Run()方法没有传递带参数委托的版本,可以通过传递lambda表达式。

        您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

           Task t4 = Task.Run(()=> TaskMethod("using Run method"));

          static void Main(string[] args) { var tf = new TaskFactory(); Task t1 = tf.StartNew(TaskMethod,"using a task factory"); Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task"); Task t3 = new Task(TaskMethod,"using a task constructor and Start"); t3.Start(); Task t4 = Task.Run(()=> TaskMethod("using Run method")); Console.ReadKey(); }

        2.同步任务

        任务不一定使用线程池中的线程,也可以使用其它线程。任务也可以同步运行,以相同的线程作为主调线程。
        示例:

              static void RunSyncTask() { TaskMethod("main thread"); var t = new Task(TaskMethod,"run sync"); t.RunSynchronously(); }

        输出:

        上面代码先在主线程上直接调用TaskMethod方法,然后在创建的Task上调用。从输出看到,主线程是一个前台线程,没有任务ID,也不是线程池中的线程。调用RunSynchronously方法时,会使用相同的线程,会创建一个任务。

        3.使用单独线程的任务

        上面将到的任务虽然不是线程池中的线程,但使用的是主线程,不是单独的,不能实现异步。
        如果任务的代码应该长时间运行,就应该使用TaskCreationOptions.LongRunning告诉任务调度器创建一个新的单独线程,而不是线程池中的线程。这个线程可以不由线程池管理。当线程来自线程池时,任务调度器可以决定等待已经运行的任务完成,然后使用这个线程,而不是在线程池中创建一个新线程。对于长时间运行的线程,任务调度器会立即知道等待它们完成是不明智的做法,会创建一个新的线程。
        示例:

        static void LongRunTask() { var t = new Task(TaskMethod,"long running",TaskCreationOptions.LongRunning); t.Start(); }

        输出:

        二.任务的结果————Future

        任务结束时,可以把一些有用的状态信息写入共享对象中。这个共享对象必须是线程安全的。另一个选项是使用返回某个结果的任务。这种任务也叫future,因为它在将来返回一个结果。这需要使用Task类的一个泛型版本。使用这个类可以定义任务返回的结果的类型。
        示例:
        使用泛型类Task<TResult>,TResult是返回类型。通过构造函数,把方法传递给Func委托,第二个参数是委托的参数。

              static void Main(string[] args) { var t = new Task<Tuple<int, int>>(TaskWithResult,Tuple.Create<int,int>(8,3)); t.Start(); Console.WriteLine(t.Result); t.Wait(); Console.WriteLine("result from task:{0},{1}", t.Result.Item1, t.Result.Item2); Console.ReadKey(); }

        由任务来调用来返回结果的方法可以声明为任何类型。

        static Tuple<int, int> TaskWithResult(object o) { Tuple<int, int> div = (Tuple<int, int>)o; int result = div.Item1 / div.Item2; int reminder = div.Item1 % div.Item2; Thread.Sleep(10000); return Tuple.Create<int, int>(result,reminder); }

        这里使用了元组(www.jb51.net/article/244045.htm).

        三.连续的任务

        通过任务,可以指定在任务完成后,应接着运行另一个特定任务。例如,一个使用前一个任务的结果的新任务,如果前一个任务失败了,这个任务就应执行一些清理工作。
        任务处理程序(前一个任务)或者不带参数,或者带一个对象参数,而连续处理程序有一个Task类型的参数,这里可以访问前一个任务的相关信息。
        示例:

        //一个任务结束时,可以启动多个任务,连续任务也可以有另一个连续的任务。 static void Main(string[] args) { Task t1 = new Task(DoFirst); Task t2 = t1.ContinueWith(DoSecond); Task t3 = t1.ContinueWith(DoSecond); Task t4= t2.ContinueWith(DoSecond); t1.Start(); Console.ReadKey(); } static void DoFirst() { Console.WriteLine("do some task:{0}",Task.CurrentId); Thread.Sleep(3000); } static void DoSecond(Task t) { Console.WriteLine("task {0} finished",t.Id); Console.WriteLine("this task id:{0}",Task.CurrentId); }

        无论前一个任务是如何结束,前面的连续任务总是在前一个任务结束时启动。使用TaskContinuationOptions枚举中的值,可以指定,连续任务只有在任务成功或失败时启动。

            Task t5 = t1.ContinueWith(DoSecond,TaskContinuationOptions.OnlyOnFaulted);

        四.任务的层次结构

        利用任务连续性,可以在一个任务结束后启动另一个任务。任务也可以构成一个层次结构。在一个任务中启动一个新的任务时,就启动了一个父/子层次结构。取消父任务,也会取消子任务。
        创建子任务与创建父任务的代码相同,唯一区别就就是子任务从另一个任务内部创建。
        示例:

        static void Main(string[] args) { Task t = new Task(ParentTask); t.Start(); Console.ReadKey(); } static void ParentTask() { Console.WriteLine("parent task id:{0}",Task.CurrentId); var child = new Task(ChildTask); child.Start(); Console.WriteLine("parent create child"); } static void ChildTask() { Console.WriteLine("child task"); }

        如果父任务在子任务之前结束,父任务的状态就是WaitingForChildrenToComplete。所有子任务也结束时,父任务的状态就是RanToCompletion.

        到此这篇关于C#多线程之任务的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持自由互联。

        本文共计2228个文字,预计阅读时间需要9分钟。

        您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

        目录一. 启动任务

        1.使用线程池的任务

        2.同步任务

        3.使用单线程的任务

        二. 任务的结束结果三. 持续的任务四. 任务的层次结构五. Parallel类的并行任务

        目录
        • 一.启动任务
          • 1.使用线程池的任务
          • 2.同步任务
          • 3.使用单独线程的任务
        • 二.任务的结果————Future
          • 三.连续的任务
            • 四.任务的层次结构

              Parallel类(www.jb51.net/article/244267.htm)的并行任务需要结束后才能运行后面的代码,如果想不等结束后在开始动作,可以使用Task类更好地控制并行动作。
              任务表示应完成的某个工作单元。这个工作单元可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主调线程。使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制。
              任务相对Parallel类提供了非常大的灵活性。例如,可以定义连续的工作——在一个任务完成后该执行什么工作。这可以根据任务成功与否来分。还可以在层次结构中安排任务。例如,父任务可以创建新的子任务。

              一.启动任务

              要启动任务,可以使用TaskFactory类或Task类的构造函数和Start()方法。Task类的构造函数在创建任务上灵活性比较大。
              在启动任务时,会创建Task类的一个实例,利用Action或Action<T>委托(不带参数或带一个参数),可以指定应运行的代码。

              1.使用线程池的任务

              线程池提供了一个后台线程的池(后面详细介绍了线程池)。线程池独自管理线程,根据需要增加或减少线程池中的线程数。线程池中的线程用于实现一些动作,之后仍然返回线程池中。
              下面介绍创建线程池的任务的四种方法:
              先定义一个要调用使用的方法:

                //避免写入控制台的操作交叉,这里使用lock关键字同步 static object taskMethodLock = new object(); static void TaskMethod(object title) { lock (taskMethodLock) { Console.WriteLine(title); Console.WriteLine("task id:{0},thread:{1}",Task.CurrentId,Thread.CurrentThread.ManagedThreadId); Console.WriteLine("is pooled thread:{0}",Thread.CurrentThread.IsThreadPoolThread); Console.WriteLine("is background thread:{0}",Thread.CurrentThread.IsBackground); } }

              (1).使用实例化的TaskFactory类,把TaskMethod方法和TaskMethod方法的参数传递给StartNew方法:

                  var tf = new TaskFactory();     Task t1 = tf.StartNew(TaskMethod,"using a task factory");

              (2).使用Task类的静态属性Factory来访问TaskFactory,以调用StartNew()方法。类似第一种,也使用了工厂,但对工厂的控制没那么全面。

                  Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task");

              (3).使用Task的构造函数。实例化Task对象时任务不会执行,只是指定Created状态。接着调用Start()方法,启动任务。

                  Task t3 = new Task(TaskMethod,"using a task constructor and Start");     t3.Start();

              (4).直接调用Task类的Run()方法启动任务。Run()方法没有传递带参数委托的版本,可以通过传递lambda表达式。

              您的问题似乎不完整,您是想询问关于C语言编程的某个具体问题吗?比如C语言的语法、编程技巧、项目开发等。请提供更具体的信息,这样我才能给出更准确的回答。

                 Task t4 = Task.Run(()=> TaskMethod("using Run method"));

                static void Main(string[] args) { var tf = new TaskFactory(); Task t1 = tf.StartNew(TaskMethod,"using a task factory"); Task t2 = Task.Factory.StartNew(TaskMethod,"using factory via a task"); Task t3 = new Task(TaskMethod,"using a task constructor and Start"); t3.Start(); Task t4 = Task.Run(()=> TaskMethod("using Run method")); Console.ReadKey(); }

              2.同步任务

              任务不一定使用线程池中的线程,也可以使用其它线程。任务也可以同步运行,以相同的线程作为主调线程。
              示例:

                    static void RunSyncTask() { TaskMethod("main thread"); var t = new Task(TaskMethod,"run sync"); t.RunSynchronously(); }

              输出:

              上面代码先在主线程上直接调用TaskMethod方法,然后在创建的Task上调用。从输出看到,主线程是一个前台线程,没有任务ID,也不是线程池中的线程。调用RunSynchronously方法时,会使用相同的线程,会创建一个任务。

              3.使用单独线程的任务

              上面将到的任务虽然不是线程池中的线程,但使用的是主线程,不是单独的,不能实现异步。
              如果任务的代码应该长时间运行,就应该使用TaskCreationOptions.LongRunning告诉任务调度器创建一个新的单独线程,而不是线程池中的线程。这个线程可以不由线程池管理。当线程来自线程池时,任务调度器可以决定等待已经运行的任务完成,然后使用这个线程,而不是在线程池中创建一个新线程。对于长时间运行的线程,任务调度器会立即知道等待它们完成是不明智的做法,会创建一个新的线程。
              示例:

              static void LongRunTask() { var t = new Task(TaskMethod,"long running",TaskCreationOptions.LongRunning); t.Start(); }

              输出:

              二.任务的结果————Future

              任务结束时,可以把一些有用的状态信息写入共享对象中。这个共享对象必须是线程安全的。另一个选项是使用返回某个结果的任务。这种任务也叫future,因为它在将来返回一个结果。这需要使用Task类的一个泛型版本。使用这个类可以定义任务返回的结果的类型。
              示例:
              使用泛型类Task<TResult>,TResult是返回类型。通过构造函数,把方法传递给Func委托,第二个参数是委托的参数。

                    static void Main(string[] args) { var t = new Task<Tuple<int, int>>(TaskWithResult,Tuple.Create<int,int>(8,3)); t.Start(); Console.WriteLine(t.Result); t.Wait(); Console.WriteLine("result from task:{0},{1}", t.Result.Item1, t.Result.Item2); Console.ReadKey(); }

              由任务来调用来返回结果的方法可以声明为任何类型。

              static Tuple<int, int> TaskWithResult(object o) { Tuple<int, int> div = (Tuple<int, int>)o; int result = div.Item1 / div.Item2; int reminder = div.Item1 % div.Item2; Thread.Sleep(10000); return Tuple.Create<int, int>(result,reminder); }

              这里使用了元组(www.jb51.net/article/244045.htm).

              三.连续的任务

              通过任务,可以指定在任务完成后,应接着运行另一个特定任务。例如,一个使用前一个任务的结果的新任务,如果前一个任务失败了,这个任务就应执行一些清理工作。
              任务处理程序(前一个任务)或者不带参数,或者带一个对象参数,而连续处理程序有一个Task类型的参数,这里可以访问前一个任务的相关信息。
              示例:

              //一个任务结束时,可以启动多个任务,连续任务也可以有另一个连续的任务。 static void Main(string[] args) { Task t1 = new Task(DoFirst); Task t2 = t1.ContinueWith(DoSecond); Task t3 = t1.ContinueWith(DoSecond); Task t4= t2.ContinueWith(DoSecond); t1.Start(); Console.ReadKey(); } static void DoFirst() { Console.WriteLine("do some task:{0}",Task.CurrentId); Thread.Sleep(3000); } static void DoSecond(Task t) { Console.WriteLine("task {0} finished",t.Id); Console.WriteLine("this task id:{0}",Task.CurrentId); }

              无论前一个任务是如何结束,前面的连续任务总是在前一个任务结束时启动。使用TaskContinuationOptions枚举中的值,可以指定,连续任务只有在任务成功或失败时启动。

                  Task t5 = t1.ContinueWith(DoSecond,TaskContinuationOptions.OnlyOnFaulted);

              四.任务的层次结构

              利用任务连续性,可以在一个任务结束后启动另一个任务。任务也可以构成一个层次结构。在一个任务中启动一个新的任务时,就启动了一个父/子层次结构。取消父任务,也会取消子任务。
              创建子任务与创建父任务的代码相同,唯一区别就就是子任务从另一个任务内部创建。
              示例:

              static void Main(string[] args) { Task t = new Task(ParentTask); t.Start(); Console.ReadKey(); } static void ParentTask() { Console.WriteLine("parent task id:{0}",Task.CurrentId); var child = new Task(ChildTask); child.Start(); Console.WriteLine("parent create child"); } static void ChildTask() { Console.WriteLine("child task"); }

              如果父任务在子任务之前结束,父任务的状态就是WaitingForChildrenToComplete。所有子任务也结束时,父任务的状态就是RanToCompletion.

              到此这篇关于C#多线程之任务的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持自由互联。