惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
V
V2EX
L
LangChain Blog
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
T
The Blog of Author Tim Ferriss
Recorded Future
Recorded Future
月光博客
月光博客
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
美团技术团队
博客园 - 【当耐特】
The Cloudflare Blog
罗磊的独立博客
GbyAI
GbyAI
A
About on SuperTechFans
腾讯CDC
宝玉的分享
宝玉的分享
I
InfoQ
V
Visual Studio Blog
Forbes - Security
Forbes - Security
P
Proofpoint News Feed
T
Troy Hunt's Blog
NISL@THU
NISL@THU
Webroot Blog
Webroot Blog
T
Threatpost
博客园 - 三生石上(FineUI控件)
S
Securelist
H
Help Net Security
小众软件
小众软件
L
Lohrmann on Cybersecurity
Cyberwarzone
Cyberwarzone
T
The Exploit Database - CXSecurity.com
量子位
博客园_首页
Scott Helme
Scott Helme
酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
J
Java Code Geeks
G
GRAHAM CLULEY
T
Tor Project blog
The GitHub Blog
The GitHub Blog
Cloudbric
Cloudbric
IT之家
IT之家
阮一峰的网络日志
阮一峰的网络日志
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Schneier on Security
Schneier on Security
V
Vulnerabilities – Threatpost
Jina AI
Jina AI

博客园 - 老码识途呀

基于.NET的Windows窗体编程之WinForms图像控件 基于.NET的Windows窗体编程之WinForms提示控件 基于.NET的Windows窗体编程之WinForms时间控件 基于.NET的Windows窗体编程之WinForms图表控件 基于.NET的Windows窗体编程之WinForms输入与显示 基于.NET的Windows窗体编程之WinForms菜单工具栏 基于.NET的Windows窗体编程之WinForms打印 基于.NET的Windows窗体编程之WinForms对话框 基于.NET的Windows窗体编程之WinForms列表控件 基于.NET的Windows窗体编程之WinForms数据表格 基于.NET的Windows窗体编程之WinForms事件简介 基于.NET的Windows窗体编程之WinForms布局简介 基于.NET的Windows窗体编程之WinForms控件简介 基于.NET的Windows窗体编程之WinForms入门简介 推荐一款基于.NET和百度飞桨的OCR识别组件 新书速递,手把手教你WPF入门与开发 推荐一种并发线程中资源同步常用方法 推荐一种异步线程执行过程中更新进度的方法 推荐一款基于.NET的进程间数据交互经典解决方案 推荐一款线程or进程间数据同步解决方案 推荐一款代码规范检查(CodeReview)神器 推荐一款高性能状态机管理解决方案 推荐一款进程间高速交换数据的解决方案 推荐一款基于.NET的进程间通信框架 推荐一款基于EF-Core的分库分表利器 推荐一种程序崩溃闪退或卡死的分析方法 推荐一款Excel读写神器之MiniExcel入门详解 推荐一款Ioc容器之Ninject入门详解 ASP.NET Core WebApi+React UI开发入门详解
推荐一种手动设置异步线程等待机制的解决方案
老码识途呀 · 2025-12-01 · via 博客园 - 老码识途呀

在实际应用中,异步线程可能需要等待另外的任务完成情况来确定本任务的完成状态。例如图像分析的结果,依赖于图像分析算法对图像的分析,在这种情况下,图像分析并非一种返回结果,根据分析返回的结果来确认图像是好的,还是坏的,进而手动设置异步线程的结果。今天我们以一个简单的小例子,简述在.NET开发中,如何通过TaskCompletionSource来手动设置异步线程的等待结果,仅供学习分享使用,如有不足之处,还请指正。

image

TaskCompletionSource概述

TaskCompletionSource<TResult> 是 .NET 中用于手动控制 Task<TResult> 完成时机的工具,常用于将事件驱动或回调模式转换为 async/await 友好形式。TaskCompletionSource有一个属性Task,用于获取当前需要等待的任务。通过TaskCompletionSource,可以设置三种返回结果,如下所示:

  • SetCanceled:将TaskCompletionSource.Task 转换为Cancel状态,并在原等待任务中抛出TaskCanceledException异常。
  • SetException:将TaskCompletionSource.Task 转换为Faluted状态,并在原等待任务中抛出对应的Exception异常。
  • SetResult:将TaskCompletionSource.Task 转换为RanToCompletion状态,并设置TResult类型的结果。
  • TrySetCanceled:尝试将TaskCompletionSource.Task 转换为Canceled状态,,并在原等待任务中抛出TaskCanceledException异常。
  • TrySetException:尝试将TaskCompletionSource.Task 转换为Faluted状态,并在原等待任务中抛出对应的Exception异常。
  • TrySetResult:将TaskCompletionSource.Task 转换为RanToCompletion状态,并设置TResult类型的结果。

对于上述设置方法,在调用时有以下两点需要注意:

  • 对于SetCanceled,SetException,SetResult方法,如果当前Task状态已经是RanToCompletion,Faulted,Canceled,则在设置时抛出InvalidOperationException。
  • 对于TrySetCanceled,TrySetException,TrySetResult,如果Task已经是RanToCompletion,Faulted,Canceled,则返回false,否则返回true。

在上述TaskCompletionSource设置返回结果的方法中,涉及到当前Task对应的状态,对于一个Task类型的任务,主要有以下几种:

  • Created‌:任务已创建但尚未启动。
  • ‌WaitingForActivation‌:任务已创建但未被激活(例如通过Start方法)。
  • ‌WaitingToRun‌:任务已激活但尚未开始执行。
  • ‌Running‌:任务正在执行中。
  • ‌WaitingForChildrenToComplete‌:任务本身已完成,但其子任务仍在运行(仅适用于父任务)。
  • ‌RanToCompletion‌:任务已成功完成。
  • ‌Canceled‌:任务因取消操作终止。
  • ‌Faulted‌:任务因未处理异常终止。 ‌

Task的主要属性,如下所示:

  • ‌Task.Status‌:获取当前任务的TaskStatus值。 ‌
  • ‌IsCanceled‌:检查任务是否因取消完成。 ‌
  • ‌IsFaulted‌:检查任务是否因异常完成。 
  • ‌IsCompleted‌:检查任务是否已完成(无论成功、取消或异常)。 ‌

TaskCompletionSource用法

接下来,以一个简单的小例子介绍TaskCompletionSource的使用方法,首先创建的一个任务异步执行Running方法,并在Running方法中等待TaskCompletionSource.Task的完成和获取结果,如下所示:

private Task task;

private TaskCompletionSource<bool> tcs;

public MainForm()
{
    InitializeComponent();
}

private void btnStart_Click(object sender, EventArgs e)
{
    tcs = new TaskCompletionSource<bool>();
    task = Task.Run(async () =>
    {
        await Running(this.tcs);
    });

}

private async Task Running(TaskCompletionSource<bool> tcs)
{
    try
    {
        this.OutputInfo("当前开始工作中");
        bool result = await tcs.Task;
        this.OutputInfo($"当前已完成工作,IsComplete={tcs.Task.IsCompleted},结果为{result}");
    }
    catch (TaskCanceledException ex)
    {
        this.OutputInfo($"当前已取消工作,IsCancelled = {tcs.Task.IsCanceled}");
        this.OutputInfo($"异常信息如下:");
        this.OutputInfo($"{ex.Message}");
    }
    catch (Exception ex2)
    {
        this.OutputInfo($"当前工作出现了异常,IsFaulted={tcs.Task.IsFaulted}");
        this.OutputInfo($"异常信息如下:");
        this.OutputInfo($"{ex2.Message}");
    }
}

设置Result

当任务正常完成时,通过调用SetResult或TrySetResult方法,将任务状态转换为RanToCompletion,Running方法中的任务正常完成。此方法接收一个参数,用于设置Task返回的结果,类型由定义TaskCompletionSource时指定的泛型确定,如下所示:

private void btnEnd_Click(object sender, EventArgs e)
{
	if (this.tcs != null && this.tcs.Task.Status==TaskStatus.WaitingForActivation)
	{
		this.tcs.SetResult(true);
	}
}

设置Canceled

当任务被取消时,通过调用SetCanceled或TrySetCanceled方法,将任务状态转换为Canceled,此时Running方法中的任务将抛出TaskCanceledException,如下所示:

private void btnCancel_Click(object sender, EventArgs e)
{
	if (this.tcs != null && this.tcs.Task.Status == TaskStatus.WaitingForActivation)
	{
		this.tcs.SetCanceled();
	}
}

设置Exception

当任务执行过程中出现异常时,通过调用SetException或TrySetException方法,将任务状态转换为Faluted,此时Running方法总的任务将抛出对应设置的Exception,如下所示:

private void btnExce_Click(object sender, EventArgs e)
{
	if (this.tcs != null && this.tcs.Task.Status == TaskStatus.WaitingForActivation)
	{
		this.tcs.SetException(new Exception("Okcoder异常出现"));
	}
}

在上述方法中,引用的Output方法为自定义方法,用于将信息输出到文本框中,如下所示:

private void OutputInfo(string msg)
{
	this.Invoke(() =>
	{
		this.txtInfo.AppendText($"{msg}\r\n");
	});
}

示例演示

在本示例中,首先有一个开始按钮,用于启动任务:

image

结束按钮,用于设置正常的任务结束,并返回结果

image

一个取消按钮,用于取消任务

image

一个异常按钮,用于设置运行过程中出现的异常信息

image

以上就是《推荐一种手动设置异步线程等待机制的解决方案》的全部内容,旨在抛砖引玉,一起学习,共同进步!