C#图像,在其他地方使用的对象错误

时间:2011-02-22 15:58:16

标签: c# multithreading image

我对C#非常陌生,请原谅我,如果我不解释这个。

我从我的电脑摄像头中检索图像,并在PictureBox中显示它们,我将它们编码为jpeg并将它们发送到共享字典。这是我的代码:

void CurrentCamera_OnImageCaptured(object sender, CameraEventArgs e)
        {
            this.pictureBoxMe.Image = e.Image;

            if (myName != "" && Form1.PicSent)
            {
                SendPic sendP = new SendPic((Image)e.Image.Clone());
                new System.Threading.Thread(new System.Threading.ThreadStart(sendP.send)).Start();
            }

        }

 public class SendPic
        {
            Image im;
            public SendPic (Image im)
            {
                this.im = im;
            }
            public void send(){

                Form1.PicSent = false;
                var memoryStream = new MemoryStream();

                im.Save(memoryStream, ImageFormat.Jpeg);

                var byteArray = memoryStream.ToArray();

                Form1.sd["/" + myName + "/video"] = byteArray;

                memoryStream.Close();
                Form1.PicSent = true;

            }
        }

问题是我得到了“对象目前在其他地方使用”。行上的错误:SendPic sendP = new SendPic((Image)e.Image.Clone());

基于我发现的其他论坛帖子,我已经更改了它,以便将图像传递给线程,这样它就是克隆。但是我仍然得到同样的错误(虽然现在崩溃之前它会持续更长时间)。

我读过一些关于锁定的内容?在这种情况下我该如何实现呢?或者我还需要做些什么吗?

感谢。

2 个答案:

答案 0 :(得分:3)

它的行为就好像OnImageCaptured方法在一个线程上运行一样。这对于相机接口来说并非不太可能。设置一个断点并使用调试器的Debug + Windows + Threads窗口来查看运行此代码的线程。

失败模式是UI线程正在访问图像以绘制图片框,同时此工作线程调用Clone()。 GDI +不允许两个线程同时访问同一个图像对象。它确实是片状的,没有告诉UI线程开始绘画的确切时刻。 PicSent是另一个等待发生的事故。

答案 1 :(得分:1)

引起我注意的一件事是SendPic类异步访问你的字典(行:Form1.sd["/" + myName + "/video"] = byteArray;)。

但是,字典和哈希表保证对写操作是线程安全的。如果您使访问字典的代码是线程安全的,那么您应该是安全的。一个简单的lock将是一种开始的方式。

有点像这样:

public class SendPic
{
    private object lockobj = new object();
    // .... whatever other code ...

    public void send()
    {
       // .... whatever previous code ...

       lock(lockobj)
       {
          // assuming that the sd dictionary already has the relevant key
          // otherwise you'd need to do a Form1.sd.Add(key, byteArray)
          Form1.sd["/" + myName + "/video"] = byteArray;
       }

       // .... whatever following code ...
    }
} 

Quote from MSDN:

  

线程安全
字典<(Of<(TKey,TValue>)>)可以支持   同时多个读者,同样长   因为集合没有被修改。   即便如此,通过一个列举   集合本质上不是一个   线程安全的程序。 在罕见的   枚举争辩的情况   与写访问,集合   必须在整个过程中锁定   枚举。 允许收集   由多个线程访问   读书和写作,你必须   实现自己的同步。