c语言中多线程编程实验(C多线程编程之Task)
c语言中多线程编程实验(C多线程编程之Task)Task实例有三种可能的最终状态3) 最终状态:Task实例有三种可能的初始状态2)中间状态:Task实例有两种可能的中间状态
1 System.Threading.Tasks.Task简介一个Task表示一个异步操作,Task的创建和执行是独立的。
只读属性:
2 Task状态和生命周期一个Task实例只会完成其生命周期一次,当Task达到它的3种可能的最终状态之一时,它就再也回不去之前的状态了。任务的生命周期从TaskStatus.Created状态真正开始。
1) 初始状态:
Task实例有三种可能的初始状态
2)中间状态:
Task实例有两种可能的中间状态
3) 最终状态:
Task实例有三种可能的最终状态
3 创建并执行任务
1)public Task StartNew(Action action)
参数:
action:要异步执行的操作委托
返回值:
已启动的 System.Threading.Tasks.Task
异常:
System.ArgumentNullException:当 action 参数为 null 时引发的异常。
2)public static Task Run(Action action)
参数:
action:表示在线程池执行的队列的任务
返回值:
已启动的 System.Threading.Tasks.Task
异常:
System.ArgumentNullException:当 action 参数为 null 时引发的异常。
3)public void Start()
启动 System.Threading.Tasks.Task,并将它安排到当前的 System.Threading.Tasks.TaskScheduler中执行。
异常:
System.ObjectDisposedException:已释放 System.Threading.Tasks.Task 实例。
System.InvalidOperationException:System.Threading.Tasks.Task 未处于有效状态,无法启动。 它可能已启动、已执行或已取消,或者可能已经不支持以直接计划的方式创建。
注意:
仅使用Task的构造器来创建Task的实例并不能启动任务,还要使用Start才能启动任务。
4)Task.Factory.StartNew与Task.Run
Task.Factory.StartNew重载方法提供更多的参数,可以控制如何计划执行任务以及如何向调试器公开计划任务的机制和控制任务的创建和执行的可选行为。
而Task.Run提供的方法则不具有上述控制机制。
4 等待任务完成1)public void Wait()
等待 System.Threading.Tasks.Task 完成执行过程
异常:
ObjectDisposedException:Task 对象已被释放。
AggregateException:System.Threading.Tasks.Task 已取消或在 System.Threading.Tasks.Task 的执行期间引发了异常。如果任务已被取消,System.AggregateException将包含其System.AggregateException.InnerExceptions 集合中的 System.OperationCanceledException。
2)public static void WaitAll(params Task[] tasks)
参数:
tasks:要等待的 Task 实例的数组
异常:
ObjectDisposedException:一个或多个 Task 中的对象 tasks 已被释放。
ArgumentNullException:tasks 参数为 null或tasks 参数包含 null 元素。
AggregateException:在至少一个 Task 实例已取消。如果任务已被取消, AggregateException 异常包含OperationCanceledException 中的异常其 AggregateException.InnerExceptions 集合。或在至少一个执行期间引发了异常 Task 实例。
说明:
主线程会等待作为参数传入的任务tasks执行结束才会执行下一条语句。
3)public static int WaitAny(params Task[] tasks)
参数:
tasks:要等待的 Task 实例的数组
异常:
System.ObjectDisposedException:System.Threading.Tasks.Task 已被释放。
System.ArgumentNullException:tasks 参数为 null。
System.ArgumentException:tasks 参数包含 null 元素。
5 取消任务使用System.Threading.CancellationToken和System.Threading.CancellationTokenSource中断Task的执行。
1)System.Threading.CancellationToken
传播有关应取消操作的通知
属性:
public bool IsCancellationRequested { get; }
方法:
public void ThrowIfCancellationRequested();
如果已请求取消此标记,则引发 System.OperationCanceledException。
异常:
System.OperationCanceledException:该标记已请求取消。
System.ObjectDisposedException:关联的System.Threading.CancellationTokenSource已被释放。
2) System.Threading.CancellationTokenSource
通知 System.Threading.CancellationToken,告知其应被取消
属性:
public CancellationToken Token { get; }:获取与此 System.Threading.CancellationTokenSource 关联的 System.Threading.CancellationToken。
异常:
System.ObjectDisposedException:已释放标记源。
方法:
public void Cancel():传达取消请求。
异常:
System.ObjectDisposedException:此 System.Threading.CancellationTokenSource 已被释放。
System.AggregateException:聚合异常包含由相关联的 System.Threading.CancellationToken 上已注册的回调引发的所有异常。
6 任务的返回值1)Task类型
在第1节中已经介绍了Task。
2)Task<TResult>类型
属性
方法
public Task ContinueWith(Action<Task<TResult>> continuationAction)
参数:
continuationAction:在 System.Threading.Tasks.Task<TResult> 完成时要运行的操作。在运行时,委托将作为一个参数传递给完成的任务。
异常:
System.ObjectDisposedException:System.Threading.Tasks.Task<TResult> 已被释放。
System.ArgumentNullException:continuationAction 参数为 null。
注意:
该方法的重载方法提供了更多的控制机制。可以传入CancellationToken、TaskContinuationOptions、TaskScheduler参数。
使用Task.Factory.StartNew方法,如果传入的委托无返回值,那么方法执行的返回结果类型其实是Task<TResult>,通过Task<TResult>类型的Result 属性可以查看返回结果。对于串联的多个任务,若后续的任务要使用上一个任务的结果,那么Task.Factory.StartNew返回值类型必须是Task<TResult>或var。
返回值可以是自定义类型。
7 TaskCreationOptions (枚举类型)用途:控制任务创建与执行的行为。
8 任务计划TaskScheduler功能:扩展任务执行计划,例如自定义任务计划程序来实现性能加速。
属性:
9 串联多个任务1)public Task ContinueWith(Action<Task> continuationAction);
参数:
continuationAction:在 System.Threading.Tasks.Task 完成时要运行的操作。 在运行时,委托将作为一个参数传递给完成的任务。
异常:
System.ObjectDisposedException:创建了 cancellationToken 的 System.Threading.CancellationTokenSource已经被释放。
System.ArgumentNullException:continuationAction 参数为 null。
2)public Task ContinueWith(Action<Task> continuationAction TaskContinuationOptions continuationOptions);
参数:
continuationAction:根据在 continuationOptions 中指定的条件运行的操作。 在运行时,委托将作为一个参数传递给完成的任务。
continuationOptions:用于设置计划延续任务的时间以及延续任务的工作方式的选项。
3)TaskContinuationOptions
enum类型,用于设置计划延续任务的时间以及延续任务的工作方式的选项。 这包括条件(如System.Threading.Tasks.TaskContinuationOptions.OnlyOnCanceled)和执行选项(如
System.Threading.Tasks.TaskContinuationOptions.ExecuteSynchronously)。
注意:
1)可以通过位操作组合使用多个值。
2)使用ContinuationOptions.None意味着不论前面的任务是否被取消,延续任务都会执行。
异常:
System.ObjectDisposedException:System.Threading.Tasks.Task 已被释放。
System.ArgumentNullException:continuationAction 参数为 null。
System.ArgumentOutOfRangeException:continuationOptions 参数为System.Threading.Tasks.TaskContinuationOptions 指定无效值。
3)子任务(嵌套任务):在父任务的委托中创建的 System.Threading.Tasks.Task 实例。 子任务包括两种:附加的子任务与分离的子任务
分离的子任务是不依赖于其父级而执行。
附加的子任务是使用 TaskCreationOptions.AttachedToParent 选项创建的,依赖于其父任务而执行。 对父任务使用TaskCreationOptions.DenyChildAttach来阻止子任务附加到父任务。
一个任务可以创建任意数量的附加的子任务和分离的子任务,这仅受系统资源限制。
不提倡创建附加的子任务,这样会大大增加程序设计的复杂性。
10 使用模式1)创建任务
基本形式:
private void CreatTask() { //创建并执行任务 Task task = new Task(() => { //具体操作 }); task.Start(); //创建并将任务加入执行计划 使用StartNew Task.Factory.StartNew(() => { //具体操作 }); //创建并将任务加入执行计划 使用Run Task.Run(() => { //具体操作 }); //安排任务 Task.Factory.StartNew(() => { //具体操作 } TaskCreationOptions.PreferFairness); } //创建附加的子任务: private void CreateTask_Parent() { //附加子任务 var taskParent = Task.Factory.StartNew(() => { //操作...... var child = Task.Factory.StartNew(() => { //具体操作 } TaskCreationOptions.AttachedToParent); }); taskParent.Wait(); //阻止附加子任务 var taskParentZ = Task.Factory.StartNew(() => { //操作...... var child = Task.Factory.StartNew(() => { //即使设置TaskCreationOptions.AttachedToParent也无法将其附加到父任务 //具体操作 } TaskCreationOptions.AttachedToParent); } TaskCreationOptions.DenyChildAttach); taskParentZ .Wait(); }
2)取消任务
public static void CancelFromExternal_Task() { CancellationTokenSource cts = new CancellationTokenSource(); //其他操作... //计算condition bool condition = ...; if (condition) cts.Cancel(); //或使用Operation2_Task(cts); Operation1_Task(cts); //其他操作... } //1 使用IsCancellationRequested属性 private static void Operation1_Task(CancellationTokenSource cts) { CancellationToken ct = cts.Token; Task.Factory.StartNew(() => { //其他操作... //return只对当前子线程有效 if (ct.IsCancellationRequested) { return; } //其他操作... } ct); } //2 使用抛异常的方式 private static void Operation2_Task(CancellationTokenSource cts) { CancellationToken ct = cts.Token; Task.Factory.StartNew(() => { //其他操作... ct.ThrowIfCancellationRequested(); //其他操作... } ct); }
3)等待任务完成
private void WaitFunc() { Task task = new Task(() => { //具体操作 }); task.Start(); task.Wait(); } private void WaitAllFunc() { Task task1 = Task.Run(() => { //具体操作 }); Task task2 = Task.Run(() => { //具体操作 }); //等待task1与task2,直到它们完成为止 Task.WaitAll(task1 task2); //等待task1与task2,如果超过1000毫秒则返回。 Task.WaitAll(new Task[] { task1 task2 } 1000); }
4)串联多个任务
private void contactTasks() { var t1 = Task.Factory.StartNew(() => { //具体操作1 //return 返回值; }); var t2 = t1.ContinueWith((t) => { //具体操作2 //return 返回值; }); var t3 = t2.ContinueWith((t) => { //具体操作3 }); var t4 = t1.ContinueWith((t) => { //具体操作4 }); var t5 = t1.ContinueWith((t) => { //具体操作5 }); Task.WaitAll(t3 t4 t5); }