You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 16:20:38