类级别声明CancellationTokenSource触发BadImageFormatException问题排查
问题描述
我有一个包含长时间运行任务的类,该任务需在UI线程触发的按钮点击时取消。为此我在类级别声明了CancellationTokenSource,启动任务时获取CancellationToken传入,取消时调用Cancel方法。但补丁更新后,点击启动任务的按钮时应用崩溃,抛出BadImageFormatException异常。请问我哪里操作有误?
public class TaskRunner { private CancellationTokenSource ctSource = new CancellationTokenSource(); private Task _task; private bool _isTaskPerforming = true; public async void BeginTask() { var ct = ctSource.Token; await PerformTask(ct); } private async Task PerformTask(CancellationToken ct) { _task = Task.Run(() => { while(_isTaskPerforming) { //Perform task related functions //Check for cancellation if(ct.IsCancellationRequested) { _isTaskPerforming = false; //other cleanup } } },ct); } public void CancelTask() { ctSource.Cancel(); } }
注:BeginTask和CancelTask均由引用该DLL的WPF应用按钮点击事件处理程序调用。
问题分析与解决方案
BadImageFormatException大多和程序集位数不匹配、损坏或版本兼容问题有关,但你的代码逻辑也存在多个关键问题,这些问题可能在补丁更新后触发异常,或与环境变化共同导致崩溃:
核心代码问题
CancellationTokenSource未重置:类级别的ctSource在调用Cancel()后就处于取消状态,无法复用。再次点击启动按钮时,传入的CancellationToken已失效,会导致任务异常。- 异步方法未正确等待:
PerformTask标记为async Task但未内部await任何操作,会导致BeginTask中的await直接完成,后台任务脱离管控,还会隐藏异常。 - 线程安全隐患:
_isTaskPerforming为未同步的共享字段,后台线程和UI线程同时访问会引发竞争条件,导致不可预期行为。 - 取消逻辑不规范:未使用TPL标准的
ct.ThrowIfCancellationRequested()触发任务取消,手动修改状态的方式不符合异步任务的取消规范。
修复后的代码
public class TaskRunner { private CancellationTokenSource _ctSource; private Task _task; private readonly object _lockObj = new object(); private bool _isTaskPerforming; public async Task BeginTask() { // 防止重复启动任务 lock (_lockObj) { if (_isTaskPerforming) return; _ctSource = new CancellationTokenSource(); _isTaskPerforming = true; } try { await PerformTask(_ctSource.Token); } finally { // 确保任务结束后清理资源 lock (_lockObj) { _isTaskPerforming = false; _ctSource?.Dispose(); _ctSource = null; } } } private async Task PerformTask(CancellationToken ct) { // 正确await后台任务,确保异步流程可控 await Task.Run(() => { while (!ct.IsCancellationRequested) { // 执行任务相关操作 // 可添加适当延迟避免CPU占用过高,比如Thread.Sleep(100); // 中途检查取消,符合TPL规范 ct.ThrowIfCancellationRequested(); } // 任务结束或取消后的清理操作放在此处 }, ct); } public void CancelTask() { lock (_lockObj) { _ctSource?.Cancel(); } } }
BadImageFormatException排查步骤
- 确认DLL与WPF应用的目标平台一致(均为x86、x64或Any CPU)
- 检查补丁更新后是否替换了错误版本的依赖程序集
- 清理解决方案并重新生成所有项目,清除残留的旧程序集
- 排查第三方库在补丁更新后是否出现位数不兼容问题
内容的提问来源于stack exchange,提问作者Rohinee Kumar
相关产品推荐
相关产品推荐

