合并图像时C#线程锁定错误

合并图像时C#线程锁定错误,c#,multithreading,locking,C#,Multithreading,Locking,我正在尝试制作一个多线程程序,它从picturebox中获取一个特定的位图,其中每个线程分析并更改其中的一部分,然后将其保存回picturebox。 我在处理共享位图对象和picturebox的指令中使用了lock(),但由于某些原因,每运行6-10次,我仍然会收到“object is Current in used Othere”(对象当前在别处使用)错误 private Object locker = new Object(); void doThread(Bitmap

我正在尝试制作一个多线程程序,它从picturebox中获取一个特定的位图,其中每个线程分析并更改其中的一部分,然后将其保存回picturebox。 我在处理共享位图对象和picturebox的指令中使用了lock(),但由于某些原因,每运行6-10次,我仍然会收到“object is Current in used Othere”(对象当前在别处使用)错误

     private Object locker = new Object();

     void doThread(Bitmap bmp2) //simplified - other references not important
     {
        //some code here
        //....  
        lock (locker)
        {
            Graphics gr = Graphics.FromImage(bmp2); //this is where i get the errors, they're related to bmp2
            gr.DrawImage(bmp, new Rectangle(0, 0, 800, 600));
            gr.Dispose();

            pictureBox1.Image = bmp2;
        }
     }

     void runThreads()
     {
        Bitmap bmp2 = new Bitmap(pictureBox1.Image);

        Thread thread1 = new Thread(delegate() { doThread(bmp2); }); 
        Thread thread2 = new Thread(delegate() { doThread(bmp2); });
        Thread thread3 = new Thread(delegate() { doThread(bmp2); });
        Thread thread4 = new Thread(delegate() { doThread(bmp2); });

        thread1.Start();
        thread2.Start();
        thread3.Start();
        thread4.Start();
    }
我已经尽可能多地阅读了lock()方法的内容,但是仍然有点不清楚,所以我可能误用了它。所以我的问题是,为什么锁不阻止线程执行指令?我用错了吗?或者有没有我可以使用的解决方法


非常感谢您提供的任何帮助。

原因是变量
pictureBox1
与GUI线程有亲缘关系。您无法从单独的后台线程访问它并更改其值。要更改该值,必须从变量关联的线程执行。这通常通过.Invoke完成

试试这个

pictureBox1.Invoke((MethodInvoker)(() => pictureBox1.Image = bmp2));

即使这样,我认为您仍然存在问题,因为bmp2值是从多个线程使用的。变量
pictureBox1
将尝试在GUI线程上呈现此值,而后台线程正在其上创建图形对象。

修复JaredPar识别的跨线程问题

然后将pictureBox1.Image设置为bmp2的副本

Image bmp2copy = bmp2.Clone();
pictureBox1.Invoke((MethodInvoker)(() => pictureBox1.Image = bmp2copy));

希望这对你有用。如果没有,您可能想考虑建立一个简单的项目来说明这个问题,这样人们就可以实际运行它并使用代码进行futz。线程问题在您的头脑中可能太难处理…

发生错误是因为您的UI线程正在使用该图像(特别是,设置pictureBox.image=someImage将导致.NET framework的ImageAnimator类查看该图像,看它是否应该对其进行动画处理(例如,对于动画.GIF图像)

同时,您的后台线程正在更改图像,从而导致WinForms代码抛出“对象当前正在其他地方使用”异常

以下代码适用于我,无论我抛出多少线程,都不会崩溃:

lock (locker)
{
  using (Graphics gr = Graphics.FromImage(bmp2))
  {
      gr.DrawImage(Resources.someImage, new Rectangle(0, 0, 800, 600));
      pictureBox1.Invoke(new Action(() => pictureBox1.Image = bmp2));
  }
}
糟了,结果也没用。扔足够多的线程,它就会崩溃

我怀疑问题与Win32在后台线程绘制位图时绘制位图有关。一个(UI)线程读取,一个(后台)线程写入。这肯定会导致问题

针对此类多线程错误的最佳修复方法通常是停止在线程之间共享数据。相反,复制数据,并让每个线程都有自己的本地副本。以下是一个示例:

lock (locker)
{
    using (Graphics gr = Graphics.FromImage(bmp2))
    {
        gr.DrawImage(Resources.someImage, new Rectangle(0, 0, 800, 600));
        var clone = bmp2.Clone() as Image;
        pictureBox1.Invoke(new Action(() => pictureBox1.Image = clone));
    }
}

gr.DrawImage行(bmp,新矩形(0,0,0,0))中的“bmp”是什么?这应该是bmp2吗?bmp是在doThread()中声明的位图函数,我正在将bmp的内容复制到bmp2。bmp存储当前线程使用过的位图的一部分。bmp2是否在锁之外的任何位置使用?我看不出会在其他位置发生错误。它不会在锁之外使用。我唯一的猜测是锁不起作用,两个线程试图同时读取它的信息e、 如果不是这样的话,我就没有主意了。但不是pictureBox。问题出在图像上。真正的问题是bmp2,它被所有4个线程读取并且“被画出来了”在每个线程中。不,不是真的。由于锁和调用,Bmp2一次由一个线程读取:要么是后台线程,要么是UI线程。上面的代码对你有用吗?它在这里工作得完美无缺。啊,我刚刚向它扔了5000多个线程,最后它崩溃了。你是对的。这里还发生了其他事情。我会看看是否能找到一个解决方案nything.我已经更新了答案,加入了一个克隆解决方案,它可以防止线程之间共享图像数据,而是为UI线程提供自己的图像副本。这可行吗?这似乎也解决了问题,希望它是好的。现在放更多线程有点困难,但我会尝试在这里发帖。非常感谢你是时候了!这是可行的!我对c#和多线程都是新手,我真的不太了解。这对我来说是一整天的“在家里玩”。再次,非常感谢!我看错了帖子,看来这还是可行的!非常感谢!