WPF项目跨线程传递Bitmap后调用Bitmap.Save抛出无效参数异常
问题解决:WPF跨线程传递Bitmap调用Save抛Invalid Parameter异常
问题原因
System.Drawing.Bitmap依赖GDI+非托管资源,本身非线程安全,你的代码存在两个核心问题:
- 传递给后台线程的是Bitmap原实例,原实例可能在UI线程的
backEnd_ImageReceived方法执行完毕后,被BackEnd回收或释放底层资源; - 跨线程访问同一个Bitmap实例时,内部状态可能因线程竞争损坏,导致调用
Save时触发参数无效异常。
解决方案
1. 传递Bitmap的独立副本而非原实例
在将Bitmap传递给后台线程前,通过Clone()方法创建完全独立的副本,确保后台线程操作的资源不受原线程影响。
2. 优化线程复用逻辑
避免重复复用同一个Thread实例,每次处理任务时创建新线程,或使用线程池管理任务(更高效)。
修改后的代码示例
修改backEnd_ImageReceived中的线程启动逻辑
// 替换原线程启动代码 if (_otherThread == null || !_otherThread.IsAlive) { // 创建Bitmap独立副本,避免跨线程访问原实例 Bitmap bitmapCopy = bitmap.Clone() as Bitmap; _otherThread = new Thread(new ParameterizedThreadStart(ProcessImage)); _otherThread.Start(bitmapCopy); }
优化ProcessImage方法(添加资源释放)
private void ProcessImage(object parameter) { if (parameter is Bitmap bitmap) { try { byte[] bytes; using (MemoryStream memoryStream = new MemoryStream()) { bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg); bytes = memoryStream.ToArray(); } // 后续业务处理逻辑 } catch (Exception e) { Debug.WriteLine("--- [ProcessImage] Exception: " + e.Message); } finally { // 手动释放Bitmap的非托管资源 bitmap.Dispose(); } } }
额外建议
- 若UI线程不需要保留原Bitmap,可在
backEnd_ImageReceived中直接转移原Bitmap资源到副本后释放原实例; - 频繁图像处理场景推荐使用
ThreadPool.QueueUserWorkItem或Task.Run替代手动创建Thread,无需手动管理线程生命周期,效率更高。
内容的提问来源于stack exchange,提问作者Tobs
相关产品推荐
相关产品推荐

