【发布时间】:2012-09-19 10:40:30
【问题描述】:
我们有一个托管的 .Net / C# 应用程序,它创建 TPL 任务以对 JPEG 图像执行 JPEG 元数据编码。每个任务都使用 TaskCreationOptions.LongRunning 选项构建,例如,
Task task = new Task( () => TaskProc(), cancelToken, TaskCreationOptions.LongRunning );
TaskProc() 利用 JpegBitmapDecoder 和 JpegBitmapEncoder 类添加 JPEG 元数据并将新图像保存到磁盘。 我们允许最多 2 个此类任务同时处于活动状态,并且此过程应无限期地继续。
在执行上述操作一段时间后,我们得到 没有足够的可用存储空间 在尝试创建 JpegBitmapDecoder 类的实例时处理此命令异常:
System.ComponentModel.Win32Exception (0x80004005):存储空间不足 可用于处理此命令 MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D wc_d)
在 MS.Win32.HwndWrapper..ctor(Int32 类样式,Int32 样式,Int32 exStyle,Int3 2 x,Int32 y,Int32 宽度,Int32 高度,字符串名称, IntPtr 父级,HwndWrapperHook [] 钩子)在 System.Windows.Threading.Dispatcher..ctor() 在 System.Windows.Threading.Dispatcher.get_CurrentDispatcher() 在 System.Windows.Media.Imaging.BitmapDecoder..ctor(流位图流, BitmapC reateOptions createOptions, BitmapCacheOption cacheOption, Guid 预期ClsId)在 System.Windows.Media.Imaging.JpegBitmapDecoder..ctor(流 bitmapStream, Bit mapCreateOptions createOptions, BitmapCacheOption 缓存选项)
该错误仅在我们使用 JpegBitmapDecoder 添加元数据时发生。换句话说,如果任务只是对位图图像进行编码并将其保存到文件中,则不会出现任何问题。使用 Process Explorer、Process Monitor 或其他诊断工具时,没有发现任何明显的问题。根本没有观察到线程、内存或句柄泄漏。出现此类错误时,无法启动新的应用程序,例如记事本、word 等。 一旦我们的应用程序终止,一切都会恢复正常。
LongRunning 的任务创建选项在 MSDN 中定义为 指定任务将是长时间运行的粗粒度操作。它向 TaskScheduler 提供了一个提示,表明可能需要超额订阅。 这意味着选择运行任务的线程可能不是来自 ThreadPool,即,它将为任务的目的而创建。其他任务创建选项将导致为任务选择 ThreadPool 线程。
经过一段时间的分析和测试,我们将任务创建选项更改为 LongRunning 以外的任何选项,例如 PreferFairness。根本没有对代码进行其他更改。这“解决”了问题,即不再出现存储空间不足的错误。
我们对 LongRunning 线程成为罪魁祸首的实际原因感到困惑。 以下是我们对此的一些问题:
为什么选择执行任务的线程应该来自线程池?如果线程终止,它的资源是否应该随着时间的推移被 GC 回收并返回给操作系统,而不管其来源如何?
LongRunning 任务和导致错误的 JpegBitmapDecoder 功能的组合有什么特别之处?
【问题讨论】:
标签: c# .net task-parallel-library